Files
SystemsMonitor/PegasusMonitor/MonitorMenuView.swift
T
2026-10-21 14:07:45 +01:00

171 lines
5.8 KiB
Swift

import SwiftUI
struct MonitorMenuView: View {
@ObservedObject var monitor: ServerMonitor
var body: some View {
VStack(alignment: .leading, spacing: 0) {
// Header
VStack(alignment: .leading, spacing: 6) {
Label("PEGASUS MONITOR", systemImage: "server.rack")
.font(.headline)
Label(
monitor.status.title,
systemImage: monitor.status.symbol
)
.foregroundStyle(monitor.status.color)
.font(.subheadline.bold())
Text("192.168.1.2")
.font(.caption)
.foregroundStyle(.secondary)
}
.padding(16)
Divider()
// Systems: vertical stack
ScrollView(.vertical) {
LazyVStack(alignment: .leading, spacing: 0) {
if let report = monitor.report {
if report.groups.isEmpty {
Text("No system groups returned by Pegasus.")
.foregroundStyle(.secondary)
.padding(16)
}
ForEach(report.groups) { group in
VStack(alignment: .leading, spacing: 5) {
Text(group.name)
.font(.system(size: 13, weight: .semibold))
.fixedSize(horizontal: false, vertical: true)
Label(
group.status.title,
systemImage: group.status.symbol
)
.font(.system(size: 12, weight: .medium))
.foregroundStyle(group.status.color)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.horizontal, 16)
.padding(.vertical, 11)
Divider()
.padding(.leading, 16)
}
} else {
Text("Waiting for Pegasus health data…")
.foregroundStyle(.secondary)
.padding(16)
}
}
}
.frame(height: 420)
Divider()
// Summary
if let report = monitor.report {
VStack(alignment: .leading, spacing: 6) {
Text(
"\(report.counts.ok) OK · " +
"\(report.counts.warn) WARN · " +
"\(report.counts.fail) FAIL"
)
.font(.system(size: 12, weight: .semibold))
Text(
monitor.lastChecked.map {
"Last checked: \($0.formatted(date: .omitted, time: .shortened))"
} ?? "Not checked"
)
.font(.caption)
.foregroundStyle(.secondary)
}
.padding(16)
}
if let error = monitor.lastError {
Text(error)
.font(.caption)
.foregroundStyle(.red)
.textSelection(.enabled)
.padding(.horizontal, 16)
.padding(.bottom, 8)
}
Divider()
// Vertical actions
VStack(alignment: .leading, spacing: 8) {
Button("Refresh") {
Task { await monitor.refresh() }
}
.disabled(monitor.isRefreshing)
Button("Diagnostics") {
monitor.showDiagnostics = true
}
Button("Settings") {
monitor.showSettings = true
}
Button("Quit") {
NSApplication.shared.terminate(nil)
}
}
.buttonStyle(.plain)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(16)
}
.frame(width: 320)
.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)
}
}