import SwiftUI struct MonitorMenuView: View { @ObservedObject var monitor: ServerMonitor var body: some View { VStack(alignment: .leading, spacing: 0) { // MARK: Header HStack(spacing: 12) { Image(systemName: "server.rack") .font(.system(size: 26)) .foregroundStyle(monitor.status.color) VStack(alignment: .leading, spacing: 4) { Text("PEGASUS MONITOR") .font(.headline) Text("192.168.1.2") .font(.caption) .foregroundStyle(.secondary) } Spacer() VStack(alignment: .trailing, spacing: 4) { Image(systemName: monitor.status.symbol) .foregroundStyle(monitor.status.color) Text(monitor.status.title) .font(.caption.bold()) .foregroundStyle(monitor.status.color) } } .padding(18) Divider() // MARK: System Status if let report = monitor.report { HStack { Text("SYSTEM") Spacer() Text("STATUS") } .font(.system(size: 10, weight: .bold)) .foregroundStyle(.secondary) .padding(.horizontal, 18) .padding(.top, 14) .padding(.bottom, 8) ScrollView { VStack(spacing: 0) { ForEach(report.groups) { group in HStack(spacing: 10) { Text(group.name) .font(.system(size: 12)) .lineLimit(1) Spacer(minLength: 8) HStack(spacing: 5) { Image(systemName: group.status.symbol) .font(.system(size: 12)) Text(group.status.title) .font(.system(size: 11, weight: .medium)) } .foregroundStyle(group.status.color) .frame(width: 90, alignment: .trailing) } .padding(.vertical, 7) Divider() .opacity(0.35) } } .padding(.horizontal, 18) } .frame(maxHeight: 460) Divider() // MARK: Overall Status HStack { Text("OVERALL STATUS") .font(.system(size: 12, weight: .bold)) Spacer() Image(systemName: monitor.status.symbol) .foregroundStyle(monitor.status.color) Text(monitor.status.title.uppercased()) .font(.system(size: 12, weight: .bold)) .foregroundStyle(monitor.status.color) } .padding(.horizontal, 18) .padding(.vertical, 12) HStack(spacing: 16) { Label( "\(report.counts.ok) OK", systemImage: "checkmark.circle.fill" ) .foregroundStyle(.green) Label( "\(report.counts.warn) WARN", systemImage: "exclamationmark.triangle.fill" ) .foregroundStyle(.orange) Label( "\(report.counts.fail) FAIL", systemImage: "xmark.circle.fill" ) .foregroundStyle(.red) } .font(.caption) .padding(.horizontal, 18) .padding(.bottom, 12) } else { ContentUnavailableView( "No Health Report", systemImage: "network", description: Text( "Check your SSH connection and refresh." ) ) .frame(height: 260) } if let error = monitor.lastError { Text(error) .font(.caption) .foregroundStyle(.red) .textSelection(.enabled) .padding(12) } Divider() // MARK: Footer HStack { Text( monitor.lastChecked.map { "Checked \($0.formatted(date: .omitted, time: .shortened))" } ?? "Not checked" ) .font(.caption) .foregroundStyle(.secondary) Spacer() if monitor.isRefreshing { ProgressView() .controlSize(.small) } Button("Refresh") { Task { await monitor.refresh() } } .disabled(monitor.isRefreshing) } .padding(14) HStack(spacing: 10) { Button("Diagnostics") { monitor.showDiagnostics = true } Button("Settings") { monitor.showSettings = true } Spacer() Button("Quit") { NSApplication.shared.terminate(nil) } } .padding(.horizontal, 14) .padding(.bottom, 14) } .frame(width: 430) .sheet(isPresented: $monitor.showDiagnostics) { DiagnosticsView(monitor: monitor) } .sheet(isPresented: $monitor.showSettings) { SettingsView(monitor: monitor) .frame(width: 480) } } } struct DiagnosticsView: View { @ObservedObject var monitor: ServerMonitor @Environment(\.dismiss) private var dismiss var body: some View { VStack(alignment: .leading, spacing: 12) { HStack { Text("Pegasus Diagnostics").font(.title2.bold()) Spacer() Button("Close") { dismiss() } } Text("Latest remote report — refresh from the menu to update") .foregroundStyle(.secondary) ScrollView { LazyVStack(alignment: .leading, spacing: 10) { ForEach(monitor.report?.checks ?? []) { check in HStack(alignment: .top) { Image(systemName: check.status.symbol).foregroundStyle(check.status.color) VStack(alignment: .leading, spacing: 2) { Text(check.name).fontWeight(.medium) Text(check.detail).font(.caption).foregroundStyle(.secondary) } Spacer() } } } } .textSelection(.enabled) } .padding(20) .frame(width: 650, height: 560) } }