diff --git a/PegasusMonitor/MonitorMenuView.swift.20261021-140032.bak b/PegasusMonitor/MonitorMenuView.swift.20261021-140032.bak deleted file mode 100644 index 27ec07e..0000000 --- a/PegasusMonitor/MonitorMenuView.swift.20261021-140032.bak +++ /dev/null @@ -1,132 +0,0 @@ -import SwiftUI - -struct MonitorMenuView: View { - @ObservedObject var monitor: ServerMonitor - @Environment(\.openSettings) private var openSettings - - var body: some View { - VStack(alignment: .leading, spacing: 0) { - HStack(spacing: 12) { - Image(systemName: "server.rack") - .font(.system(size: 26, weight: .semibold)) - .foregroundStyle(.tint) - VStack(alignment: .leading, spacing: 3) { - Text("PEGASUS MONITOR") - .font(.headline) - Text("192.168.1.2 · Remote server health") - .font(.caption) - .foregroundStyle(.secondary) - } - Spacer() - if monitor.isRefreshing { ProgressView().controlSize(.small) } - } - .padding(18) - Divider() - - if let report = monitor.report { - ScrollView { - VStack(alignment: .leading, spacing: 10) { - ForEach(report.groups) { group in - HStack(spacing: 8) { - Image(systemName: group.status.symbol) - .foregroundStyle(group.status.color) - .frame(width: 22) - Text(group.name) - .font(.system(size: 13)) - Spacer() - } - .help(group.missing.isEmpty ? group.status.title : "Missing checks: \(group.missing.joined(separator: ", "))") - } - } - .padding(.horizontal, 18) - .padding(.vertical, 14) - } - .frame(maxHeight: 375) - Divider() - HStack { - Image(systemName: monitor.status.symbol) - .foregroundStyle(monitor.status.color) - Text("OVERALL: \(monitor.status.title.uppercased())") - .font(.system(size: 13, weight: .bold)) - Spacer() - Text("\(report.counts.ok) OK · \(report.counts.warn) WARN · \(report.counts.fail) FAIL") - .font(.caption2.monospacedDigit()) - .foregroundStyle(.secondary) - } - .padding(.horizontal, 18) - .padding(.vertical, 12) - } else { - ContentUnavailableView("No health report", systemImage: "network", description: Text("Check SSH configuration and refresh.")) - .frame(height: 220) - } - - if let error = monitor.lastError { - Text(error) - .font(.caption) - .foregroundStyle(.red) - .textSelection(.enabled) - .padding(.horizontal, 18) - .padding(.bottom, 10) - } - Divider() - HStack { - Text(monitor.lastChecked.map { "Checked \($0.formatted(date: .omitted, time: .shortened))" } ?? "Not checked yet") - .font(.caption) - .foregroundStyle(.secondary) - Spacer() - Button { Task { await monitor.refresh() } } label: { - Label("Refresh", systemImage: "arrow.clockwise") - } - .disabled(monitor.isRefreshing) - } - .padding(.horizontal, 18) - .padding(.vertical, 8) - - HStack { - Button("Full Diagnostics") { monitor.showDiagnostics = true } - Spacer() - Button("Settings") { openSettings() } - Button("Quit") { NSApplication.shared.terminate(nil) } - } - .padding(.horizontal, 18) - .padding(.bottom, 12) - } - .sheet(isPresented: $monitor.showDiagnostics) { - DiagnosticsView(monitor: monitor) - } - } -} - -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) - } -} diff --git a/PegasusMonitor/MonitorMenuView.swift.20261021-140144.bak b/PegasusMonitor/MonitorMenuView.swift.20261021-140144.bak deleted file mode 100644 index 2d48753..0000000 --- a/PegasusMonitor/MonitorMenuView.swift.20261021-140144.bak +++ /dev/null @@ -1,136 +0,0 @@ -import SwiftUI - -struct MonitorMenuView: View { - @ObservedObject var monitor: ServerMonitor - @Environment(\.openSettings) private var openSettings - - var body: some View { - VStack(alignment: .leading, spacing: 0) { - HStack(spacing: 12) { - Image(systemName: "server.rack") - .font(.system(size: 26, weight: .semibold)) - .foregroundStyle(.tint) - VStack(alignment: .leading, spacing: 3) { - Text("PEGASUS MONITOR") - .font(.headline) - Text("192.168.1.2 · Remote server health") - .font(.caption) - .foregroundStyle(.secondary) - } - Spacer() - if monitor.isRefreshing { ProgressView().controlSize(.small) } - } - .padding(18) - Divider() - - if let report = monitor.report { - ScrollView { - VStack(alignment: .leading, spacing: 10) { - ForEach(report.groups) { group in - HStack(spacing: 8) { - Image(systemName: group.status.symbol) - .foregroundStyle(group.status.color) - .frame(width: 22) - Text(group.name) - .font(.system(size: 13)) - Spacer() - } - .help(group.missing.isEmpty ? group.status.title : "Missing checks: \(group.missing.joined(separator: ", "))") - } - } - .padding(.horizontal, 18) - .padding(.vertical, 14) - } - .frame(maxHeight: 375) - Divider() - HStack { - Image(systemName: monitor.status.symbol) - .foregroundStyle(monitor.status.color) - Text("OVERALL: \(monitor.status.title.uppercased())") - .font(.system(size: 13, weight: .bold)) - Spacer() - Text("\(report.counts.ok) OK · \(report.counts.warn) WARN · \(report.counts.fail) FAIL") - .font(.caption2.monospacedDigit()) - .foregroundStyle(.secondary) - } - .padding(.horizontal, 18) - .padding(.vertical, 12) - } else { - ContentUnavailableView("No health report", systemImage: "network", description: Text("Check SSH configuration and refresh.")) - .frame(height: 220) - } - - if let error = monitor.lastError { - Text(error) - .font(.caption) - .foregroundStyle(.red) - .textSelection(.enabled) - .padding(.horizontal, 18) - .padding(.bottom, 10) - } - Divider() - HStack { - Text(monitor.lastChecked.map { "Checked \($0.formatted(date: .omitted, time: .shortened))" } ?? "Not checked yet") - .font(.caption) - .foregroundStyle(.secondary) - Spacer() - Button { Task { await monitor.refresh() } } label: { - Label("Refresh", systemImage: "arrow.clockwise") - } - .disabled(monitor.isRefreshing) - } - .padding(.horizontal, 18) - .padding(.vertical, 8) - - HStack { - Button("Full Diagnostics") { monitor.showDiagnostics = true } - Spacer() - Button("Settings") { monitor.showSettings = true } - Button("Quit") { NSApplication.shared.terminate(nil) } - } - .padding(.horizontal, 18) - .padding(.bottom, 12) - } - .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) - } -} diff --git a/PegasusMonitor/MonitorMenuView.swift.20261021-140334.bak b/PegasusMonitor/MonitorMenuView.swift.20261021-140334.bak deleted file mode 100644 index 526267c..0000000 --- a/PegasusMonitor/MonitorMenuView.swift.20261021-140334.bak +++ /dev/null @@ -1,171 +0,0 @@ -import SwiftUI - -struct MonitorMenuView: View { - @ObservedObject var monitor: ServerMonitor - @Environment(\.openSettings) private var openSettings - - var body: some View { - VStack(alignment: .leading, spacing: 0) { - HStack(spacing: 12) { - Image(systemName: "server.rack") - .font(.system(size: 26, weight: .semibold)) - .foregroundStyle(.tint) - VStack(alignment: .leading, spacing: 3) { - Text("PEGASUS MONITOR") - .font(.headline) - HStack(spacing: 6) { - Text("192.168.1.2") - .foregroundStyle(.secondary) - - Image(systemName: monitor.status.symbol) - .foregroundStyle(monitor.status.color) - - Text(monitor.status.title.uppercased()) - .foregroundStyle(monitor.status.color) - .fontWeight(.semibold) - } - .font(.caption) - } - Spacer() - if monitor.isRefreshing { ProgressView().controlSize(.small) } - } - .padding(18) - Divider() - - if let report = monitor.report { - ScrollView { - VStack(alignment: .leading, spacing: 10) { - // Main system status table - HStack { - Text("SYSTEM") - Spacer() - Text("STATUS") - } - .font(.system(size: 10, weight: .semibold)) - .foregroundStyle(.secondary) - .padding(.bottom, 5) - - ForEach(report.groups) { group in - HStack(spacing: 10) { - - Text(group.name) - .font(.system(size: 12)) - .lineLimit(1) - .minimumScaleFactor(0.85) - - Spacer(minLength: 8) - - HStack(spacing: 5) { - Image(systemName: group.status.symbol) - .font(.system(size: 11)) - - Text(group.status.title) - .font(.system(size: 11, weight: .medium)) - } - .foregroundStyle(group.status.color) - .frame(width: 86, alignment: .trailing) - } - .padding(.vertical, 3) - .help( - group.missing.isEmpty - ? group.status.title - : "Missing checks: \(group.missing.joined(separator: ", "))" - ) - } - } - .padding(.horizontal, 18) - .padding(.vertical, 14) - } - .frame(maxHeight: 375) - Divider() - HStack { - Image(systemName: monitor.status.symbol) - .foregroundStyle(monitor.status.color) - Text("OVERALL: \(monitor.status.title.uppercased())") - .font(.system(size: 13, weight: .bold)) - Spacer() - Text("\(report.counts.ok) OK · \(report.counts.warn) WARN · \(report.counts.fail) FAIL") - .font(.caption2.monospacedDigit()) - .foregroundStyle(.secondary) - } - .padding(.horizontal, 18) - .padding(.vertical, 12) - } else { - ContentUnavailableView("No health report", systemImage: "network", description: Text("Check SSH configuration and refresh.")) - .frame(height: 220) - } - - if let error = monitor.lastError { - Text(error) - .font(.caption) - .foregroundStyle(.red) - .textSelection(.enabled) - .padding(.horizontal, 18) - .padding(.bottom, 10) - } - Divider() - HStack { - Text(monitor.lastChecked.map { "Checked \($0.formatted(date: .omitted, time: .shortened))" } ?? "Not checked yet") - .font(.caption) - .foregroundStyle(.secondary) - Spacer() - Button { Task { await monitor.refresh() } } label: { - Label("Refresh", systemImage: "arrow.clockwise") - } - .disabled(monitor.isRefreshing) - } - .padding(.horizontal, 18) - .padding(.vertical, 8) - - HStack { - Button("Full Diagnostics") { monitor.showDiagnostics = true } - Spacer() - Button("Settings") { monitor.showSettings = true } - Button("Quit") { NSApplication.shared.terminate(nil) } - } - .padding(.horizontal, 18) - .padding(.bottom, 12) - } - .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) - } -} diff --git a/PegasusMonitor/MonitorMenuView.swift.20261021-140459.bak b/PegasusMonitor/MonitorMenuView.swift.20261021-140459.bak deleted file mode 100644 index 3921406..0000000 --- a/PegasusMonitor/MonitorMenuView.swift.20261021-140459.bak +++ /dev/null @@ -1,256 +0,0 @@ -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) - } -} diff --git a/PegasusMonitor/SettingsView.swift.20261021-140032.bak b/PegasusMonitor/SettingsView.swift.20261021-140032.bak deleted file mode 100644 index bcef95a..0000000 --- a/PegasusMonitor/SettingsView.swift.20261021-140032.bak +++ /dev/null @@ -1,40 +0,0 @@ -import SwiftUI - -struct SettingsView: View { - @ObservedObject var monitor: ServerMonitor - @AppStorage("server.host") private var host = "192.168.1.2" - @AppStorage("server.user") private var user = "mag" - @AppStorage("server.port") private var port = "22" - @AppStorage("server.keyFile") private var keyFile = "" - @AppStorage("monitor.intervalMinutes") private var intervalMinutes = 5 - @AppStorage("monitor.notifications") private var notifications = true - - var body: some View { - Form { - TextField("Host", text: $host) - TextField("SSH user", text: $user) - TextField("SSH port", text: $port) - TextField("SSH key path (optional)", text: $keyFile) - .help("Leave blank to use your SSH agent or ~/.ssh/config") - Picker("Refresh interval", selection: $intervalMinutes) { - Text("1 minute").tag(1) - Text("5 minutes").tag(5) - Text("10 minutes").tag(10) - Text("15 minutes").tag(15) - Text("30 minutes").tag(30) - } - Toggle("Notify when server becomes unhealthy", isOn: $notifications) - HStack { - Spacer() - Button("Apply and Refresh") { - monitor.configureTimer() - Task { await monitor.refresh() } - } - } - Text("SSH must authenticate without prompts. Server requires /usr/local/bin/pegasus-health-json accessible via sudo -n. Host keys are verified using your existing SSH known_hosts file.") - .font(.caption) - .foregroundStyle(.secondary) - } - .padding(20) - } -}