// Timestamp let now = Date() timestampLabel.stringValue = timeFormatter.string(from: now) // SVC lightSvc.state = c.svcReachable ? .green : .red labelSvc.stringValue = "svc: \(cfg.svcHost):\(cfg.svcPort) \(c.svcReachable ? "✓" : "✗") \(c.svcLatency >= 0 ? "(\(c.svcLatency) ms)" : "")" labelSvc.toolTip = c.tooltipForSvc() // K3s aggregate: retropie + pi let aggCount = (c.raspberryReachable ? 1 : 0) + (c.piReachable ? 1 : 0) lightK3s.state = aggCount == 2 ? .green : (aggCount == 1 ? .yellow : .red) labelK3s.stringValue = "k3s: \(cfg.retropieHost) \(c.raspberryReachable ? "✓" : "✗"), \(cfg.piHost) \(c.piReachable ? "✓" : "✗")" labelK3s.toolTip = c.tooltipForAggregateK3s() // Local lightLocal.state = c.localReachable ? .green : .red labelLocal.stringValue = "local: \(cfg.localHost):\(cfg.localPort) \(c.localReachable ? "✓" : "✗") \(c.localLatency >= 0 ? "(\(c.localLatency) ms)" : "")" labelLocal.toolTip = c.tooltipForLocal() // Port forwards if let m = pfManager { let running = m.runningCount let total = m.details.count lightPF.state = m.allRunning ? .green : .red labelPF.stringValue = total > 0 ? "kubectl port-forwards: \(running)/\(total) running" : "kubectl port-forwards: none configured" labelPF.toolTip = "Managed processes: \(running)/\(total) running" renderPFDetails(m) } else { lightPF.state = .red labelPF.stringValue = "kubectl port-forwards: disabled" labelPF.toolTip = "To enable, set pf.enabled=true in prole.properties" clearPFDetails() } needsLayout = true } // MARK: - PF Details rendering private func clearPFDetails() { pfDetailsStack.arrangedSubviews.forEach { v in pfDetailsStack.removeArrangedSubview(v) v.removeFromSuperview() } } private func renderPFDetails(_ manager: PortForwardManager) { clearPFDetails() let details = manager.details guard !details.isEmpty else { return } for d in details { let dot = TrafficLight() dot.state = d.running ? .green : .red let pidText: String if let pid = d.pid, pid > 0 { pidText = "PID \(pid)" } else { pidText = "PID -" } let label = NSTextField(labelWithString: "\(pidText) • \(d.running ? "running" : "stopped") — \(d.command)") label.font = NSFont.systemFont(ofSize: NSFont.systemFontSize(for: .small)) label.textColor = .secondaryLabelColor label.lineBreakMode = .byTruncatingMiddle let row = NSStackView(views: [dot, label]) row.orientation = .horizontal row.alignment = .centerY row.spacing = 8 row.translatesAutoresizingMaskIntoConstraints = false pfDetailsStack.addArrangedSubview(row) } } }