/ src / renderer / components / pages / McpProcessPage.vue
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>