McpDxtPage.vue
1 <script setup lang="ts"> 2 import { ref, watch } from 'vue' 3 import { FileTransfer } from '@/renderer/utils' 4 import { useMcpStore } from '@/renderer/store/mcp' 5 const mcpStore = useMcpStore() 6 7 const props = defineProps({ 8 modelValue: { 9 type: Boolean, 10 required: true 11 } 12 }) 13 14 const emit = defineEmits(['update:modelValue']) 15 16 const internalDialog = ref(props.modelValue) 17 18 const files = ref([] as File[]) 19 const loading = ref(false) 20 21 watch(files, (val) => { 22 console.log(val) 23 }) 24 25 const filterFiles = () => { 26 files.value = files.value.filter((file) => { 27 return file.name.toLowerCase().endsWith('.mcpb') 28 }) 29 } 30 31 const processFiles = async () => { 32 try { 33 loading.value = true 34 console.log(files) 35 const fileList = files.value 36 files.value = [] 37 38 const promises = fileList.map(async (file) => { 39 const arrayBuffer = await file.arrayBuffer() 40 return FileTransfer.request({ 41 name: file.name, 42 data: arrayBuffer 43 }) 44 }) 45 46 await Promise.all(promises) 47 48 await FileTransfer.response(fileList.length) 49 50 await window.dxtManifest?.refresh() 51 await window.mcpServers?.refresh() 52 mcpStore.version++ 53 } finally { 54 loading.value = false 55 closeDialog() 56 } 57 } 58 59 watch( 60 () => props.modelValue, 61 (newVal) => { 62 internalDialog.value = newVal 63 } 64 ) 65 66 watch(internalDialog, (newVal) => { 67 emit('update:modelValue', newVal) 68 }) 69 70 const closeDialog = () => { 71 files.value = [] 72 internalDialog.value = false 73 } 74 </script> 75 76 <template> 77 <v-dialog v-model="internalDialog" persistent max-width="80vw" max-height="80vh" scrollable> 78 <v-card :title="$t('dxt.title')"> 79 <template #append> 80 <v-btn 81 icon="mdi-close-box" 82 rounded="lg" 83 color="error" 84 variant="text" 85 @click="closeDialog" 86 ></v-btn> 87 </template> 88 <v-divider></v-divider> 89 <v-card-text> 90 <slot></slot> 91 <v-card variant="flat" :loading="loading"> 92 <v-file-upload 93 v-model="files" 94 :disabled="loading" 95 color="light-grey" 96 class="mb-2" 97 density="compact" 98 accept=".mcpb" 99 clearable 100 show-size 101 multiple 102 scrim="primary" 103 @change="filterFiles" 104 > 105 <template #icon> 106 <v-icon class="mb-2" size="x-small" icon="mdi-upload"></v-icon> 107 </template> 108 <template #title> 109 <div class="text-grey text-h6"> .MCPB {{ $t('mcp.file') }} </div> 110 </template> 111 </v-file-upload> 112 </v-card> 113 </v-card-text> 114 115 <v-card-actions> 116 <v-spacer></v-spacer> 117 118 <v-btn 119 variant="plain" 120 rounded="lg" 121 :disabled="files.length === 0" 122 icon="mdi-delete-outline" 123 color="error" 124 @click="files.length = 0" 125 ></v-btn> 126 127 <v-btn 128 variant="plain" 129 rounded="lg" 130 :disabled="files.length === 0" 131 icon="mdi-content-save-plus" 132 color="success" 133 @click="processFiles()" 134 ></v-btn> 135 </v-card-actions> 136 </v-card> 137 </v-dialog> 138 </template>