package cc.unitmesh.devins.idea.components.status import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import cc.unitmesh.agent.config.PreloadingStatus import cc.unitmesh.devins.idea.compose.IdeaLaunchedEffect import cc.unitmesh.devins.idea.services.IdeaToolConfigService import cc.unitmesh.devins.idea.toolwindow.IdeaAgentViewModel import cc.unitmesh.devins.idea.theme.IdeaAutoDevColors import com.intellij.openapi.project.Project import org.jetbrains.jewel.foundation.theme.JewelTheme import org.jetbrains.jewel.ui.component.Text /** * Tool loading status bar for displaying MCP tools and SubAgents status. * * Note: Uses LaunchedEffect-based manual collection instead of collectAsState() * to avoid ClassLoader conflicts between plugin's coroutines and IntelliJ's * bundled Compose runtime. */ @Composable fun IdeaToolLoadingStatusBar( viewModel: IdeaAgentViewModel, project: Project, modifier: Modifier = Modifier ) { // Use manual state collection to avoid ClassLoader conflicts with collectAsState() var mcpPreloadingMessage by remember { mutableStateOf("") } var mcpPreloadingStatus by remember { mutableStateOf(PreloadingStatus(false, emptyList(), 0)) } var configVersion by remember { mutableStateOf(0L) } IdeaLaunchedEffect(viewModel, project = project) { viewModel.mcpPreloadingMessage.collect { mcpPreloadingMessage = it } } IdeaLaunchedEffect(viewModel, project = project) { viewModel.mcpPreloadingStatus.collect { mcpPreloadingStatus = it } } // Observe tool config service for configuration changes val toolConfigService = remember { IdeaToolConfigService.getInstance(project) } IdeaLaunchedEffect(toolConfigService, project = project) { toolConfigService.configVersion.collect { configVersion = it } } // Recompute when preloading status OR config version changes val toolStatus = remember(mcpPreloadingStatus, configVersion) { viewModel.getToolLoadingStatus() } Row( modifier = modifier .background(JewelTheme.globalColors.panelBackground.copy(alpha = 0.8f)) .padding(horizontal = 12.dp, vertical = 6.dp), horizontalArrangement = Arrangement.spacedBy(16.dp), verticalAlignment = Alignment.CenterVertically ) { // SubAgents status IdeaToolStatusChip( label = "SubAgents", count = toolStatus.subAgentsEnabled, total = toolStatus.subAgentsTotal, isLoading = false, color = IdeaAutoDevColors.Blue.c400 ) // MCP Tools status IdeaToolStatusChip( label = "MCP Tools", count = toolStatus.mcpToolsEnabled, total = if (toolStatus.isLoading) -1 else toolStatus.mcpToolsTotal, isLoading = toolStatus.isLoading, color = if (!toolStatus.isLoading && toolStatus.mcpToolsEnabled > 0) IdeaAutoDevColors.Green.c400 else JewelTheme.globalColors.text.info ) Spacer(modifier = Modifier.weight(1f)) // Status message if (mcpPreloadingMessage.isNotEmpty()) { Text( text = mcpPreloadingMessage, style = JewelTheme.defaultTextStyle.copy( fontSize = 11.sp, color = JewelTheme.globalColors.text.info ), maxLines = 1 ) } else if (!toolStatus.isLoading && toolStatus.mcpServersLoaded > 0) { Text( text = "✓ All tools ready", style = JewelTheme.defaultTextStyle.copy( fontSize = 11.sp, color = IdeaAutoDevColors.Green.c400 ) ) } } } /** * Individual tool status chip with count indicator. */ @Composable fun IdeaToolStatusChip( label: String, count: Int, total: Int, isLoading: Boolean, color: Color, modifier: Modifier = Modifier ) { Row( modifier = modifier, verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp) ) { // Status indicator dot Box( modifier = Modifier .size(8.dp) .background( color = if (isLoading) JewelTheme.globalColors.text.info.copy(alpha = 0.5f) else color, shape = CircleShape ) ) val totalDisplay = if (total < 0) "..." else total.toString() Text( text = "$label ($count/$totalDisplay)", style = JewelTheme.defaultTextStyle.copy( fontSize = 11.sp, color = if (isLoading) JewelTheme.globalColors.text.info.copy(alpha = 0.7f) else JewelTheme.globalColors.text.info ) ) } }