McpProcessPage.vue
1 <script setup lang="ts"> 2 import { McpEvent } from '@/renderer/utils' 3 import { useMcpStore } from '@/renderer/store/mcp' 4 import { useLayoutStore } from '@/renderer/store/layout' 5 import { ref, watch, computed } from 'vue' 6 import { IpcMcpInitRequestCallback } from '@/types/ipc' 7 8 const layoutStore = useLayoutStore() 9 const mcpStore = useMcpStore() 10 11 interface ProgressItem { 12 messages: string[] 13 status: 'pending' | 'error' | 'success' 14 } 15 16 const progressMap = ref<Record<string, ProgressItem>>({}) 17 18 const mcpDialog = ref(false) 19 20 const handleProgress: IpcMcpInitRequestCallback = (_event, progress) => { 21 const name = progress.callback.name 22 const message = progress.callback.message 23 const status = progress.callback.status 24 25 console.log(progressMap.value[name], progress.callback) 26 27 if (!progressMap.value[name]) { 28 progressMap.value[name] = { 29 messages: [], 30 status: 'pending' 31 } 32 } 33 if (message) { 34 progressMap.value[name].messages.push(message) 35 } 36 if (status !== 'pending') { 37 progressMap.value[name].status = status 38 } 39 } 40 41 McpEvent.watch(handleProgress) 42 43 const isLoading = computed(() => layoutStore.mcpLoading) 44 45 const allSuccess = computed(() => { 46 return Object.entries(progressMap.value).every( 47 ([key, item]) => item.status === 'success' || !mcpStore.checkList.includes(key) 48 ) 49 }) 50 51 watch(isLoading, (newVal, oldVal) => { 52 if (newVal) { 53 progressMap.value = {} 54 mcpDialog.value = true 55 } else { 56 setTimeout(() => { 57 console.log(progressMap.value) 58 if (allSuccess.value || oldVal === 'stop') { 59 // If all server are started successful, or all servers are forced to stop 60 // no need to stick the dialog for process visualization 61 mcpDialog.value = false 62 } 63 }, 500) 64 } 65 }) 66 </script> 67 68 <template> 69 <v-dialog v-model="mcpDialog" persistent max-width="80vw" max-height="80vh" scrollable> 70 <v-card> 71 <v-card-text> 72 <v-timeline align="start" density="compact"> 73 <v-timeline-item 74 v-for="(value, name, key) in progressMap" 75 :key="key" 76 :dot-color="value.status" 77 size="x-small" 78 > 79 <div class="mb-4"> 80 <div class="font-weight-normal"> 81 <strong>{{ name }}</strong> 82 </div> 83 84 <div v-for="message in value.messages" :key="message">{{ message }}</div> 85 </div> 86 </v-timeline-item> 87 </v-timeline> 88 </v-card-text> 89 <v-card-actions> 90 <v-spacer></v-spacer> 91 <v-icon-btn 92 icon="mdi-close-box" 93 color="error" 94 variant="plain" 95 rounded="lg" 96 @click="mcpDialog = false" 97 ></v-icon-btn> 98 </v-card-actions> 99 </v-card> 100 </v-dialog> 101 </template>