mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-12 10:55:51 +02:00
feat(index-status): add composable for monitoring cache index status using SSE
This commit is contained in:
parent
d815e292db
commit
2d3a5e2a16
8 changed files with 75 additions and 107 deletions
49
app/src/composables/useIndexStatus.ts
Normal file
49
app/src/composables/useIndexStatus.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import cacheIndex from '@/api/cache_index'
|
||||||
|
import { SSE } from 'sse.js'
|
||||||
|
import { useSSE } from './useSSE'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composable for monitoring cache index status
|
||||||
|
* Provides a way to track indexing/scanning status through SSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface IndexStatus {
|
||||||
|
isScanning: Ref<boolean>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup SSE connection to monitor indexing status
|
||||||
|
*/
|
||||||
|
export function setupIndexStatus() {
|
||||||
|
const { connect, disconnect, sseInstance } = useSSE()
|
||||||
|
|
||||||
|
const isScanning = ref(false)
|
||||||
|
|
||||||
|
disconnect()
|
||||||
|
|
||||||
|
const sse = cacheIndex.index_status()
|
||||||
|
|
||||||
|
if (sse instanceof SSE) {
|
||||||
|
connect({
|
||||||
|
url: '', // Not needed as we already have the SSE instance
|
||||||
|
token: '', // Not needed as we already have the SSE instance
|
||||||
|
onMessage: data => {
|
||||||
|
isScanning.value = data.scanning
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
// Reconnection is handled by useSSE
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Manually assign the SSE instance since we're using a pre-created one
|
||||||
|
sseInstance.value = sse
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('indexStatus', {
|
||||||
|
isScanning,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useIndexStatus(): IndexStatus {
|
||||||
|
return inject<IndexStatus>('indexStatus')!
|
||||||
|
}
|
|
@ -1,6 +1,4 @@
|
||||||
import type { NginxPerformanceInfo } from '@/api/ngx'
|
import type { NginxPerformanceInfo } from '@/api/ngx'
|
||||||
import type { Ref } from 'vue'
|
|
||||||
import { computed } from 'vue'
|
|
||||||
|
|
||||||
export function usePerformanceMetrics(nginxInfo: Ref<NginxPerformanceInfo | undefined>) {
|
export function usePerformanceMetrics(nginxInfo: Ref<NginxPerformanceInfo | undefined>) {
|
||||||
// Format numbers to a more readable form
|
// Format numbers to a more readable form
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { SSEvent } from 'sse.js'
|
import type { SSEvent } from 'sse.js'
|
||||||
import { SSE } from 'sse.js'
|
import { SSE } from 'sse.js'
|
||||||
import { onUnmounted, shallowRef } from 'vue'
|
|
||||||
|
|
||||||
export interface SSEOptions {
|
export interface SSEOptions {
|
||||||
url: string
|
url: string
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import settings from '@/api/settings'
|
import settings from '@/api/settings'
|
||||||
import PageHeader from '@/components/PageHeader/PageHeader.vue'
|
import PageHeader from '@/components/PageHeader/PageHeader.vue'
|
||||||
|
import { setupIndexStatus } from '@/composables/useIndexStatus'
|
||||||
import { useSettingsStore } from '@/pinia'
|
import { useSettingsStore } from '@/pinia'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
|
@ -41,6 +42,8 @@ settings.get_server_name().then(r => {
|
||||||
server_name.value = r.name
|
server_name.value = r.name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
setupIndexStatus()
|
||||||
|
|
||||||
const breadList = ref([])
|
const breadList = ref([])
|
||||||
|
|
||||||
provide('breadList', breadList)
|
provide('breadList', breadList)
|
||||||
|
|
|
@ -88,7 +88,7 @@ function handleCancel() {
|
||||||
</AButton>
|
</AButton>
|
||||||
|
|
||||||
<AModal
|
<AModal
|
||||||
v-model:visible="modalVisible"
|
v-model:open="modalVisible"
|
||||||
:title="$gettext('Delete Certificate')"
|
:title="$gettext('Delete Certificate')"
|
||||||
:confirm-loading="confirmLoading"
|
:confirm-loading="confirmLoading"
|
||||||
:ok-button-props="{
|
:ok-button-props="{
|
||||||
|
|
|
@ -1,20 +1,16 @@
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import type { CustomRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
|
import type { CustomRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
|
||||||
import type { Column } from '@/components/StdDesign/types'
|
import type { Column } from '@/components/StdDesign/types'
|
||||||
import type { SSE, SSEvent } from 'sse.js'
|
|
||||||
import cacheIndex from '@/api/cache_index'
|
|
||||||
import nginxLog from '@/api/nginx_log'
|
import nginxLog from '@/api/nginx_log'
|
||||||
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
|
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
|
||||||
import { input, select } from '@/components/StdDesign/StdDataEntry'
|
import { input, select } from '@/components/StdDesign/StdDataEntry'
|
||||||
|
import { useIndexStatus } from '@/composables/useIndexStatus'
|
||||||
import { CheckCircleOutlined, LoadingOutlined } from '@ant-design/icons-vue'
|
import { CheckCircleOutlined, LoadingOutlined } from '@ant-design/icons-vue'
|
||||||
import { Tag } from 'ant-design-vue'
|
import { Tag } from 'ant-design-vue'
|
||||||
import { onMounted, onUnmounted, ref } from 'vue'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const isScanning = ref(false)
|
const { isScanning } = useIndexStatus()
|
||||||
const stdCurdRef = ref()
|
const stdCurdRef = ref()
|
||||||
const sse = ref<SSE>()
|
|
||||||
|
|
||||||
const columns: Column[] = [
|
const columns: Column[] = [
|
||||||
{
|
{
|
||||||
|
@ -63,50 +59,6 @@ function viewLog(record: { type: string, path: string }) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect to SSE endpoint and setup handlers
|
|
||||||
async function setupSSE() {
|
|
||||||
if (sse.value) {
|
|
||||||
sse.value.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
sse.value = cacheIndex.index_status()
|
|
||||||
|
|
||||||
// Handle incoming messages
|
|
||||||
if (sse.value) {
|
|
||||||
sse.value.onmessage = (e: SSEvent) => {
|
|
||||||
try {
|
|
||||||
if (!e.data)
|
|
||||||
return
|
|
||||||
|
|
||||||
const data = JSON.parse(e.data)
|
|
||||||
isScanning.value = data.scanning
|
|
||||||
|
|
||||||
stdCurdRef.value.get_list()
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error('Error parsing SSE message:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sse.value.onerror = () => {
|
|
||||||
// Reconnect on error
|
|
||||||
setTimeout(() => {
|
|
||||||
setupSSE()
|
|
||||||
}, 5000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
setupSSE()
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
if (sse.value) {
|
|
||||||
sse.value.close()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
import type { EnvGroup } from '@/api/env_group'
|
import type { EnvGroup } from '@/api/env_group'
|
||||||
import type { Site } from '@/api/site'
|
import type { Site } from '@/api/site'
|
||||||
import type { Column } from '@/components/StdDesign/types'
|
import type { Column } from '@/components/StdDesign/types'
|
||||||
import type { SSE, SSEvent } from 'sse.js'
|
|
||||||
import cacheIndex from '@/api/cache_index'
|
|
||||||
import env_group from '@/api/env_group'
|
import env_group from '@/api/env_group'
|
||||||
import site from '@/api/site'
|
import site from '@/api/site'
|
||||||
import EnvGroupTabs from '@/components/EnvGroupTabs/EnvGroupTabs.vue'
|
import EnvGroupTabs from '@/components/EnvGroupTabs/EnvGroupTabs.vue'
|
||||||
import StdBatchEdit from '@/components/StdDesign/StdDataDisplay/StdBatchEdit.vue'
|
import StdBatchEdit from '@/components/StdDesign/StdDataDisplay/StdBatchEdit.vue'
|
||||||
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
|
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
|
||||||
|
import { useIndexStatus } from '@/composables/useIndexStatus'
|
||||||
import { ConfigStatus } from '@/constants'
|
import { ConfigStatus } from '@/constants'
|
||||||
import InspectConfig from '@/views/config/InspectConfig.vue'
|
import InspectConfig from '@/views/config/InspectConfig.vue'
|
||||||
import columns from '@/views/site/site_list/columns'
|
import columns from '@/views/site/site_list/columns'
|
||||||
|
@ -20,15 +19,15 @@ const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const table = ref()
|
const table = ref()
|
||||||
const inspect_config = ref()
|
const inspectConfig = ref()
|
||||||
|
|
||||||
const envGroupId = ref(Number.parseInt(route.query.env_group_id as string) || 0)
|
const envGroupId = ref(Number.parseInt(route.query.env_group_id as string) || 0)
|
||||||
const envGroups = ref([]) as Ref<EnvGroup[]>
|
const envGroups = ref([]) as Ref<EnvGroup[]>
|
||||||
const isScanning = ref(false)
|
|
||||||
const sse = ref<SSE>()
|
const { isScanning } = useIndexStatus()
|
||||||
|
|
||||||
watch(route, () => {
|
watch(route, () => {
|
||||||
inspect_config.value?.test()
|
inspectConfig.value?.test()
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
@ -48,55 +47,11 @@ onMounted(async () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
setupSSE()
|
|
||||||
})
|
|
||||||
|
|
||||||
// Connect to SSE endpoint and setup handlers
|
|
||||||
async function setupSSE() {
|
|
||||||
if (sse.value) {
|
|
||||||
sse.value.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
sse.value = cacheIndex.index_status()
|
|
||||||
|
|
||||||
// Handle incoming messages
|
|
||||||
if (sse.value) {
|
|
||||||
sse.value.onmessage = (e: SSEvent) => {
|
|
||||||
try {
|
|
||||||
if (!e.data)
|
|
||||||
return
|
|
||||||
|
|
||||||
const data = JSON.parse(e.data)
|
|
||||||
isScanning.value = data.scanning
|
|
||||||
|
|
||||||
table.value.get_list()
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error('Error parsing SSE message:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sse.value.onerror = () => {
|
|
||||||
// Reconnect on error
|
|
||||||
setTimeout(() => {
|
|
||||||
setupSSE()
|
|
||||||
}, 5000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
if (sse.value) {
|
|
||||||
sse.value.close()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function destroy(site_name: string) {
|
function destroy(site_name: string) {
|
||||||
site.destroy(site_name).then(() => {
|
site.destroy(site_name).then(() => {
|
||||||
table.value.get_list()
|
table.value.get_list()
|
||||||
message.success($gettext('Delete site: %{site_name}', { site_name }))
|
message.success($gettext('Delete site: %{site_name}', { site_name }))
|
||||||
inspect_config.value?.test()
|
inspectConfig.value?.test()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +88,7 @@ function handleBatchUpdated() {
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<InspectConfig ref="inspect_config" />
|
<InspectConfig ref="inspectConfig" />
|
||||||
|
|
||||||
<EnvGroupTabs v-model:active-key="envGroupId" :env-groups="envGroups" />
|
<EnvGroupTabs v-model:active-key="envGroupId" :env-groups="envGroups" />
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,12 @@ import StdBatchEdit from '@/components/StdDesign/StdDataDisplay/StdBatchEdit.vue
|
||||||
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
|
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
|
||||||
import { actualValueRender, datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
|
import { actualValueRender, datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
|
||||||
import { input, selector } from '@/components/StdDesign/StdDataEntry'
|
import { input, selector } from '@/components/StdDesign/StdDataEntry'
|
||||||
|
import { useIndexStatus } from '@/composables/useIndexStatus'
|
||||||
import { ConfigStatus } from '@/constants'
|
import { ConfigStatus } from '@/constants'
|
||||||
import InspectConfig from '@/views/config/InspectConfig.vue'
|
import InspectConfig from '@/views/config/InspectConfig.vue'
|
||||||
import envGroupColumns from '@/views/environments/group/columns'
|
import envGroupColumns from '@/views/environments/group/columns'
|
||||||
import StreamDuplicate from '@/views/stream/components/StreamDuplicate.vue'
|
import StreamDuplicate from '@/views/stream/components/StreamDuplicate.vue'
|
||||||
|
import { CheckCircleOutlined, LoadingOutlined } from '@ant-design/icons-vue'
|
||||||
import { Badge, message } from 'ant-design-vue'
|
import { Badge, message } from 'ant-design-vue'
|
||||||
|
|
||||||
const columns: Column[] = [{
|
const columns: Column[] = [{
|
||||||
|
@ -169,12 +171,22 @@ function handleBatchUpdated() {
|
||||||
table.value?.get_list()
|
table.value?.get_list()
|
||||||
table.value?.resetSelection()
|
table.value?.resetSelection()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { isScanning } = useIndexStatus()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ACard :title="$gettext('Manage Streams')">
|
<ACard :title="$gettext('Manage Streams')">
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<a @click="add">{{ $gettext('Add') }}</a>
|
<div class="flex items-center cursor-default">
|
||||||
|
<a class="mr-4" @click="add">{{ $gettext('Add') }}</a>
|
||||||
|
<template v-if="isScanning">
|
||||||
|
<LoadingOutlined class="mr-2" spin />{{ $gettext('Indexing...') }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<CheckCircleOutlined class="mr-2" />{{ $gettext('Indexed') }}
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<InspectConfig ref="inspect_config" />
|
<InspectConfig ref="inspect_config" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue