From cf587aa0573ac4f34e1effe70108a9eca82093ac Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Tue, 24 Mar 2026 21:48:23 -0500 Subject: v1.0 --- Rune/Views/Domains/RecordAddView.swift | 144 +++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 Rune/Views/Domains/RecordAddView.swift (limited to 'Rune/Views/Domains/RecordAddView.swift') diff --git a/Rune/Views/Domains/RecordAddView.swift b/Rune/Views/Domains/RecordAddView.swift new file mode 100644 index 0000000..8dfa81d --- /dev/null +++ b/Rune/Views/Domains/RecordAddView.swift @@ -0,0 +1,144 @@ +import SwiftUI + +struct RecordAddView: View { + let domainName: String + @ObservedObject var viewModel: DomainViewModel + let client: NjallaClient + + @Environment(\.dismiss) private var dismiss + + @State private var draft = DNSRecordDraft() + @State private var localErrorMessage: String? + var body: some View { + Form { + DNSRecordFormSections(draft: $draft) + + Section { + Button("Save") { + Task { + await save() + } + } + .disabled(viewModel.isSaving || !draft.canSubmit) + } + } + .navigationTitle("Add Record") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .cancellationAction) { + Button("Cancel", role: .cancel) { + dismiss() + } + } + } + .onChange(of: draft.type) { oldValue, newValue in + guard oldValue != newValue else { return } + draft.resetTypeSpecificFields() + } + .alert("API Error", isPresented: localErrorBinding) { + Button("OK", role: .cancel) {} + } message: { + Text(localErrorMessage ?? "") + } + } + + private func save() async { + do { + try await viewModel.addRecord(for: domainName, draft: draft, client: client) + dismiss() + } catch is CancellationError { + return + } catch { + if (error as? URLError)?.code == .cancelled { + return + } + localErrorMessage = error.localizedDescription + } + } + + private var localErrorBinding: Binding { + Binding( + get: { localErrorMessage != nil }, + set: { newValue in + if !newValue { + localErrorMessage = nil + } + } + ) + } +} + +struct DNSRecordFormSections: View { + @Binding var draft: DNSRecordDraft + + var body: some View { + Section("Record") { + Picker("Type", selection: $draft.type) { + ForEach(DNSRecordType.allCases) { type in + Text(type.rawValue).tag(type) + } + } + + TextField("Name", text: $draft.name) + .textInputAutocapitalization(.never) + .autocorrectionDisabled() + } + + if draft.type.usesContent { + Section("Content") { + TextField("Content", text: $draft.content, axis: .vertical) + .textInputAutocapitalization(.never) + .autocorrectionDisabled() + } + } + + if draft.type.usesTTL { + Section("TTL") { + TextField("TTL", text: $draft.ttl) + .keyboardType(.numberPad) + } + } + + if draft.type.usesPriority { + Section("Priority") { + TextField("Priority", text: $draft.prio) + .keyboardType(.numberPad) + } + } + + if draft.type.usesWeight { + Section("Weight") { + TextField("Weight", text: $draft.weight) + .keyboardType(.numberPad) + } + } + + if draft.type.usesPort { + Section("Port") { + TextField("Port", text: $draft.port) + .keyboardType(.numberPad) + } + } + + if draft.type.usesTarget { + Section("Target") { + TextField("Target", text: $draft.target) + .textInputAutocapitalization(.never) + .autocorrectionDisabled() + } + } + + if draft.type.usesSSHFields { + Section { + TextField("SSH Algorithm", text: $draft.sshAlgorithm) + .keyboardType(.numberPad) + TextField("SSH Type", text: $draft.sshType) + .keyboardType(.numberPad) + } header: { + Text("SSHFP") + } footer: { + Text("Algorithm values: 1-5. Type values: 1-2.") + } + } + } +} -- cgit v1.2.3