- Add McpTransport enum with Http and Stdio variants - Update McpServerConfig to support both transport types - Implement stdio process spawning and JSON-RPC communication - Store tool descriptors with full metadata (name, description, schema) - Maintain backwards compatibility with existing HTTP MCPs This enables using community MCP servers that use stdio transport (which is the standard for most MCP servers).
156 lines
4.1 KiB
Swift
156 lines
4.1 KiB
Swift
//
|
|
// StatusBadge.swift
|
|
// OpenAgentDashboard
|
|
//
|
|
// Status indicator badges with semantic colors
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
enum StatusType {
|
|
case pending
|
|
case running
|
|
case active
|
|
case completed
|
|
case failed
|
|
case cancelled
|
|
case idle
|
|
case error
|
|
case connected
|
|
case disconnected
|
|
case connecting
|
|
|
|
var color: Color {
|
|
switch self {
|
|
case .pending, .idle:
|
|
return Theme.textMuted
|
|
case .running, .active, .connecting:
|
|
return Theme.accent
|
|
case .completed, .connected:
|
|
return Theme.success
|
|
case .failed, .error:
|
|
return Theme.error
|
|
case .cancelled, .disconnected:
|
|
return Theme.textTertiary
|
|
}
|
|
}
|
|
|
|
var backgroundColor: Color {
|
|
color.opacity(0.15)
|
|
}
|
|
|
|
var label: String {
|
|
switch self {
|
|
case .pending: return "Pending"
|
|
case .running: return "Running"
|
|
case .active: return "Active"
|
|
case .completed: return "Completed"
|
|
case .failed: return "Failed"
|
|
case .cancelled: return "Cancelled"
|
|
case .idle: return "Idle"
|
|
case .error: return "Error"
|
|
case .connected: return "Connected"
|
|
case .disconnected: return "Disconnected"
|
|
case .connecting: return "Connecting"
|
|
}
|
|
}
|
|
|
|
var icon: String {
|
|
switch self {
|
|
case .pending: return "clock"
|
|
case .running, .connecting: return "arrow.trianglehead.2.clockwise"
|
|
case .active: return "circle.fill"
|
|
case .completed: return "checkmark.circle.fill"
|
|
case .failed, .error: return "xmark.circle.fill"
|
|
case .cancelled: return "slash.circle"
|
|
case .idle: return "moon.fill"
|
|
case .connected: return "wifi"
|
|
case .disconnected: return "wifi.slash"
|
|
}
|
|
}
|
|
|
|
var shouldPulse: Bool {
|
|
switch self {
|
|
case .running, .active, .connecting:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
struct StatusBadge: View {
|
|
let status: StatusType
|
|
var showIcon: Bool = true
|
|
var compact: Bool = false
|
|
|
|
var body: some View {
|
|
HStack(spacing: compact ? 4 : 6) {
|
|
if showIcon {
|
|
Image(systemName: status.icon)
|
|
.font(.system(size: compact ? 10 : 12, weight: .medium))
|
|
.symbolEffect(.pulse, options: status.shouldPulse ? .repeating : .nonRepeating)
|
|
}
|
|
Text(status.label)
|
|
.font(.system(size: compact ? 10 : 11, weight: .semibold))
|
|
.textCase(.uppercase)
|
|
}
|
|
.foregroundStyle(status.color)
|
|
.padding(.horizontal, compact ? 8 : 10)
|
|
.padding(.vertical, compact ? 4 : 6)
|
|
.background(status.backgroundColor)
|
|
.clipShape(Capsule())
|
|
}
|
|
}
|
|
|
|
struct StatusDot: View {
|
|
let status: StatusType
|
|
var size: CGFloat = 8
|
|
|
|
var body: some View {
|
|
Circle()
|
|
.fill(status.color)
|
|
.frame(width: size, height: size)
|
|
.overlay {
|
|
if status.shouldPulse {
|
|
Circle()
|
|
.stroke(status.color.opacity(0.5), lineWidth: 2)
|
|
.scaleEffect(1.5)
|
|
.opacity(0.5)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
VStack(spacing: 16) {
|
|
HStack(spacing: 8) {
|
|
StatusBadge(status: .pending)
|
|
StatusBadge(status: .running)
|
|
StatusBadge(status: .completed)
|
|
}
|
|
|
|
HStack(spacing: 8) {
|
|
StatusBadge(status: .failed)
|
|
StatusBadge(status: .cancelled)
|
|
StatusBadge(status: .active)
|
|
}
|
|
|
|
HStack(spacing: 8) {
|
|
StatusBadge(status: .connected, compact: true)
|
|
StatusBadge(status: .disconnected, compact: true)
|
|
StatusBadge(status: .connecting, compact: true)
|
|
}
|
|
|
|
Divider()
|
|
|
|
HStack(spacing: 16) {
|
|
ForEach([StatusType.active, .completed, .failed, .idle], id: \.label) { status in
|
|
StatusDot(status: status)
|
|
}
|
|
}
|
|
}
|
|
.padding()
|
|
.background(Theme.backgroundPrimary)
|
|
}
|