11<script setup lang="ts">
2- import { ref , onMounted , onUnmounted , watch } from ' vue'
2+ import { ref , computed , onMounted , onUnmounted , watch } from ' vue'
33import { useI18n } from ' vue-i18n'
44import { useRouter , useRoute } from ' vue-router'
55import { useBreadcrumbs } from ' @/composables/useBreadcrumbs'
@@ -41,6 +41,7 @@ const servers = ref<McpServer[]>([])
4141const isLoading = ref (true )
4242const isSearching = ref (false )
4343const error = ref <string | null >(null )
44+ const deletedServerIds = ref <Set <string >>(new Set ())
4445
4546// Search and filter state
4647const searchQuery = ref (' ' )
@@ -97,6 +98,11 @@ const pagination = ref<PaginationMeta>({
9798// Selection state
9899const selectedServerIds = ref <string []>([])
99100
101+ // Filter out servers that are queued for deletion
102+ const visibleServers = computed (() => {
103+ return servers .value .filter (server => ! deletedServerIds .value .has (server .id ))
104+ })
105+
100106// Visible filters state (lifted from child to preserve across loading)
101107const visibleFilters = ref <Set <string >>(new Set ())
102108
@@ -163,15 +169,21 @@ const handleDeleteServer = async (serverId: string): Promise<void> => {
163169
164170 await McpCatalogService .deleteGlobalServer (serverId )
165171
166- toast .success (t (' mcpCatalog.messages.deletionQueued' , { name: serverName }))
172+ // Optimistically add to deleted IDs
173+ deletedServerIds .value .add (serverId )
167174
168- // Refresh the table
169- if (hasTextSearch ()) {
170- await searchServers ()
171- } else {
172- await fetchServers ()
173- }
175+ // Store in EventBus for persistence
176+ const deletedIds = Array .from (deletedServerIds .value )
177+ eventBus .setState (' deleted_server_ids' , deletedIds )
178+
179+ // Clear selection if deleted server was selected
180+ selectedServerIds .value = selectedServerIds .value .filter (id => id !== serverId )
181+
182+ toast .success (t (' mcpCatalog.messages.deletionQueued' , { name: serverName }))
174183 } catch (err ) {
184+ // Remove from deleted IDs on error
185+ deletedServerIds .value .delete (serverId )
186+
175187 const errorMessage = err instanceof Error ? err .message : ' Unknown error'
176188 toast .error (t (' mcpCatalog.messages.deleteError' , { error: errorMessage }))
177189 throw err // Re-throw so the dialog knows deletion failed
@@ -182,6 +194,18 @@ const handleBulkDeleteServers = async (serverIds: string[]): Promise<void> => {
182194 try {
183195 const result = await McpCatalogService .bulkDeleteGlobalServers (serverIds )
184196
197+ // Add queued servers to deleted IDs
198+ const queuedServerIds = new Set (result .jobs .map (job => job .server_id ))
199+ queuedServerIds .forEach (id => deletedServerIds .value .add (id ))
200+
201+ // Update storage
202+ const deletedIds = Array .from (deletedServerIds .value )
203+ eventBus .setState (' deleted_server_ids' , deletedIds )
204+
205+ // Update pagination count
206+ totalItems .value = Math .max (0 , totalItems .value - result .total_queued )
207+ selectedServerIds .value = []
208+
185209 if (result .total_skipped > 0 ) {
186210 toast .success (t (' mcpCatalog.bulkDelete.partialSuccess' , {
187211 queued: result .total_queued ,
@@ -192,15 +216,6 @@ const handleBulkDeleteServers = async (serverIds: string[]): Promise<void> => {
192216 queued: result .total_queued
193217 }))
194218 }
195-
196- // Optimistically remove deleted servers from the UI
197- // (they're queued for deletion in background jobs, not immediately deleted from DB)
198- const queuedServerIds = new Set (result .jobs .map (job => job .server_id ))
199- servers .value = servers .value .filter (server => ! queuedServerIds .has (server .id ))
200- totalItems .value = Math .max (0 , totalItems .value - result .total_queued )
201-
202- // Clear selection
203- selectedServerIds .value = []
204219 } catch (err ) {
205220 const errorMessage = err instanceof Error ? err .message : ' Unknown error'
206221 toast .error (t (' mcpCatalog.bulkDelete.error' , { error: errorMessage }))
@@ -541,6 +556,16 @@ const fetchLanguages = async () => {
541556onMounted (async () => {
542557 setBreadcrumbs ([{ label: t (' mcpCatalog.title' ) }])
543558
559+ // Load deleted IDs from storage on mount
560+ const storedDeletedIds = eventBus .getState <string []>(' deleted_server_ids' , []) || []
561+ deletedServerIds .value = new Set (storedDeletedIds )
562+
563+ // Check for deletion query params
564+ const deletedId = route .query .deletedId as string
565+ if (deletedId ) {
566+ deletedServerIds .value .add (deletedId )
567+ }
568+
544569 await Promise .all ([
545570 fetchServers (),
546571 fetchRuntimes (),
@@ -572,12 +597,26 @@ onMounted(async () => {
572597
573598 // Listen for server creation from add page
574599 eventBus .on (' mcp-server-created' , handleServerCreated )
600+
601+ // Listen for MCP_SERVER_DELETED event to clean up
602+ eventBus .on (' mcp-server-deleted' , (data : { serverId? : string ; server? : { id: string } }) => {
603+ // Remove from deleted IDs when actually deleted
604+ const serverId = data .serverId || data .server ?.id
605+ if (serverId ) {
606+ deletedServerIds .value .delete (serverId )
607+
608+ // Update storage
609+ const deletedIds = Array .from (deletedServerIds .value )
610+ eventBus .setState (' deleted_server_ids' , deletedIds )
611+ }
612+ })
575613})
576614
577615onUnmounted (() => {
578616 // Clean up event listeners
579617 eventBus .off (' mcp-catalog-updated' )
580618 eventBus .off (' mcp-server-created' , handleServerCreated )
619+ eventBus .off (' mcp-server-deleted' )
581620})
582621 </script >
583622
@@ -614,7 +653,7 @@ onUnmounted(() => {
614653 <!-- Servers Table Component -->
615654 <McpServerTableColumns
616655 :is-loading =" isLoading"
617- :servers =" servers "
656+ :servers =" visibleServers "
618657 :selected-source =" selectedSource"
619658 :search-query =" searchQuery"
620659 :is-searching =" isSearching"
0 commit comments