import SwiftUI struct ONUListView: View { let connection: MCMSConnection @State private var vm: ONUListViewModel private let title: String init(connection: MCMSConnection, stateFilter: ONULifecycleState? = nil, title: String = "ONUs") { self.connection = connection self.title = title _vm = State(initialValue: ONUListViewModel(connection: connection, stateFilter: stateFilter)) } var body: some View { @Bindable var vm = vm Group { switch vm.phase { case .idle: LoadingView(label: "Loading ONUs…") case .loading where vm.onus.isEmpty: LoadingView(label: "Loading ONUs…") case .failed(let msg): ErrorStateView(message: msg) { Task { await vm.load() } } default: list } } .navigationTitle(title) .searchable(text: $vm.search, prompt: "Name, serial, or OLT") .task { if vm.phase == .idle { await vm.load() } } .refreshable { await vm.load() } } private var list: some View { List(vm.filtered) { onu in NavigationLink { ONUDetailView(connection: connection, onuId: onu.id) } label: { row(onu) } } .listStyle(.plain) .overlay { if vm.filtered.isEmpty { if vm.search.isEmpty { ContentUnavailableView("No ONUs", systemImage: "point.3.connected.trianglepath.dotted") } else { ContentUnavailableView.search(text: vm.search) } } } } private func row(_ onu: ONUStateDoc) -> some View { HStack { VStack(alignment: .leading, spacing: 4) { Text(onu.displayName).font(.body.weight(.medium)) if let sub = subtitle(onu) { Text(sub).font(.caption).foregroundStyle(.secondary) } } Spacer() StateBadge(text: onu.lifecycle.label, color: onu.lifecycle.color) } } /// Secondary line: the serial (shown only when a name is the title) and parent OLT. private func subtitle(_ onu: ONUStateDoc) -> String? { var parts: [String] = [] if onu.resolvedName != nil { parts.append(onu.id) } if let olt = onu.parentOLT { parts.append("OLT \(olt)") } return parts.isEmpty ? nil : parts.joined(separator: " · ") } }