useIndexProgress.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import type { IndexProgress } from '../indexing/components/IndexProgressBar.vue'
  2. import { useWebSocketEventBus } from '@/composables/useWebSocketEventBus'
  3. export interface IndexProgressData {
  4. log_path: string
  5. progress: number
  6. stage: string
  7. status: string
  8. elapsed_time: number
  9. estimated_remain: number
  10. }
  11. export interface IndexCompleteData {
  12. log_path: string
  13. success: boolean
  14. duration: number
  15. total_lines: number
  16. indexed_size: number
  17. error?: string
  18. }
  19. export function useIndexProgress() {
  20. const { subscribe } = useWebSocketEventBus()
  21. // Store progress for each log file
  22. const progressMap = ref<Map<string, IndexProgress>>(new Map())
  23. // Global indexing state
  24. const isGlobalIndexing = ref(false)
  25. const globalProgress = ref<{
  26. totalFiles: number
  27. completedFiles: number
  28. currentFile?: string
  29. progress: number
  30. }>({
  31. totalFiles: 0,
  32. completedFiles: 0,
  33. progress: 0,
  34. })
  35. // Subscribe to progress events
  36. subscribe<IndexProgressData>('nginx_log_index_progress', data => {
  37. // Ignore status_update events - these are just status changes, not actual progress
  38. if (data.stage === 'status_update') {
  39. // If there's no actual indexing progress, remove any existing progress bar
  40. if (data.status !== 'indexing') {
  41. progressMap.value.delete(data.log_path)
  42. updateGlobalProgress()
  43. }
  44. return
  45. }
  46. const progress: IndexProgress = {
  47. logPath: data.log_path,
  48. progress: data.progress,
  49. stage: data.stage,
  50. status: data.status,
  51. elapsedTime: data.elapsed_time,
  52. estimatedRemain: data.estimated_remain,
  53. }
  54. progressMap.value.set(data.log_path, progress)
  55. // Update global progress
  56. updateGlobalProgress()
  57. })
  58. // Subscribe to completion events
  59. subscribe<IndexCompleteData>('nginx_log_index_complete', data => {
  60. if (data.success) {
  61. // Keep progress for a short time to show completion, then remove
  62. setTimeout(() => {
  63. progressMap.value.delete(data.log_path)
  64. updateGlobalProgress()
  65. }, 3000)
  66. }
  67. else {
  68. // Show error state
  69. const errorProgress: IndexProgress = {
  70. logPath: data.log_path,
  71. progress: 0,
  72. stage: 'error',
  73. status: 'error',
  74. elapsedTime: data.duration,
  75. estimatedRemain: 0,
  76. }
  77. progressMap.value.set(data.log_path, errorProgress)
  78. // Remove error state after delay
  79. setTimeout(() => {
  80. progressMap.value.delete(data.log_path)
  81. updateGlobalProgress()
  82. }, 5000)
  83. }
  84. })
  85. // Subscribe to processing status events for global state
  86. subscribe<{ nginx_log_indexing: boolean }>('processing_status', data => {
  87. isGlobalIndexing.value = data.nginx_log_indexing
  88. if (!data.nginx_log_indexing) {
  89. // Clear all progress when indexing stops
  90. progressMap.value.clear()
  91. updateGlobalProgress()
  92. }
  93. })
  94. function updateGlobalProgress() {
  95. const activeFiles = Array.from(progressMap.value.values())
  96. globalProgress.value.totalFiles = activeFiles.length
  97. globalProgress.value.completedFiles = activeFiles.filter(p => p.status === 'completed').length
  98. if (activeFiles.length > 0) {
  99. const currentFile = activeFiles.find(p => p.status === 'running')
  100. globalProgress.value.currentFile = currentFile?.logPath
  101. // Calculate average progress
  102. const totalProgress = activeFiles.reduce((sum, p) => sum + p.progress, 0)
  103. globalProgress.value.progress = totalProgress / activeFiles.length
  104. }
  105. else {
  106. globalProgress.value.currentFile = undefined
  107. globalProgress.value.progress = 0
  108. }
  109. }
  110. function getProgressForFile(logPath: string): IndexProgress | undefined {
  111. return progressMap.value.get(logPath)
  112. }
  113. function isFileIndexing(logPath: string): boolean {
  114. const progress = progressMap.value.get(logPath)
  115. return progress?.status === 'running'
  116. }
  117. function clearProgress(logPath: string) {
  118. progressMap.value.delete(logPath)
  119. updateGlobalProgress()
  120. }
  121. function clearAllProgress() {
  122. progressMap.value.clear()
  123. updateGlobalProgress()
  124. }
  125. return {
  126. // Reactive data
  127. progressMap: readonly(progressMap),
  128. isGlobalIndexing: readonly(isGlobalIndexing),
  129. globalProgress: readonly(globalProgress),
  130. // Methods
  131. getProgressForFile,
  132. isFileIndexing,
  133. clearProgress,
  134. clearAllProgress,
  135. }
  136. }