krz/rune

an ios client for njalla

clone: git clone https://gitbay.org/krz/rune.git

main: Rune/Views/Domains/RecordListView.swift · raw

  1import SwiftUI
  2
  3struct RecordListView: View {
  4    let domainName: String
  5    @ObservedObject var viewModel: DomainViewModel
  6    let client: NjallaClient
  7
  8    @State private var showingAddRecord = false
  9
 10    var body: some View {
 11        List {
 12            if let errorMessage = viewModel.recordsErrorMessage {
 13                Section {
 14                    InlineErrorView(message: errorMessage, retryTitle: "Retry Records") {
 15                        Task {
 16                            await viewModel.loadRecords(for: domainName, client: client)
 17                        }
 18                    }
 19                    .listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
 20                }
 21            }
 22
 23            if viewModel.isLoadingRecords && viewModel.records.isEmpty {
 24                Section {
 25                    HStack {
 26                        Spacer()
 27                        ProgressView("Loading Records")
 28                        Spacer()
 29                    }
 30                }
 31            } else if viewModel.records.isEmpty {
 32                Section {
 33                    ContentUnavailableView(
 34                        "No Records",
 35                        systemImage: "list.bullet",
 36                        description: Text("No DNS records for this domain yet. Add a record to get started.")
 37                    )
 38                }
 39            } else {
 40                ForEach(viewModel.records) { record in
 41                    NavigationLink {
 42                        RecordEditView(domainName: domainName, record: record, viewModel: viewModel, client: client)
 43                    } label: {
 44                        RecordRow(record: record)
 45                    }
 46                }
 47            }
 48        }
 49        .listStyle(.insetGrouped)
 50        .navigationTitle("DNS Records")
 51        .navigationBarTitleDisplayMode(.inline)
 52        .toolbar {
 53            Button {
 54                showingAddRecord = true
 55            } label: {
 56                Label("Add Record", systemImage: "plus")
 57            }
 58        }
 59        .sheet(isPresented: $showingAddRecord) {
 60            NavigationStack {
 61                RecordAddView(domainName: domainName, viewModel: viewModel, client: client)
 62            }
 63        }
 64        .task {
 65            await viewModel.loadRecords(for: domainName, client: client)
 66        }
 67        .onAppear {
 68            viewModel.startAutoRefreshRecords(for: domainName, client: client)
 69        }
 70        .onDisappear {
 71            viewModel.stopAutoRefreshRecords()
 72        }
 73        .refreshable {
 74            await viewModel.loadRecords(for: domainName, client: client)
 75        }
 76        .alert("Request Failed", isPresented: mutationErrorBinding) {
 77            Button("OK", role: .cancel) {}
 78        } message: {
 79            Text(viewModel.mutationErrorMessage ?? "")
 80        }
 81    }
 82
 83    private var mutationErrorBinding: Binding<Bool> {
 84        Binding(
 85            get: { viewModel.mutationErrorMessage != nil },
 86            set: { newValue in
 87                if !newValue {
 88                    viewModel.dismissMutationError()
 89                }
 90            }
 91        )
 92    }
 93}
 94
 95private struct RecordRow: View {
 96    let record: DNSRecord
 97
 98    var body: some View {
 99        VStack(alignment: .leading, spacing: 4) {
100            Text("\(record.type) \(record.name)")
101                .font(.headline)
102            if let detail = [record.content, record.target].compactMap({ $0 }).first, !detail.isEmpty {
103                Text(detail)
104                    .font(.subheadline)
105                    .foregroundStyle(.secondary)
106            }
107        }
108        .padding(.vertical, 4)
109    }
110}