summaryrefslogtreecommitdiff
path: root/Rune/Views/Domains/RecordEditView.swift
blob: fceaaba25a781714a369b8dec7c7f2b4c32ae2f5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import SwiftUI

struct RecordEditView: View {
    let domainName: String
    let record: DNSRecord
    @ObservedObject var viewModel: DomainViewModel
    let client: NjallaClient

    @Environment(\.dismiss) private var dismiss

    @State private var draft: DNSRecordDraft
    @State private var showingDeleteConfirmation = false

    init(domainName: String, record: DNSRecord, viewModel: DomainViewModel, client: NjallaClient) {
        self.domainName = domainName
        self.record = record
        self.viewModel = viewModel
        self.client = client
        _draft = State(initialValue: DNSRecordDraft(record: record))
    }

    var body: some View {
        Form {
            DNSRecordFormSections(draft: $draft)

            Section {
                Button("Save") {
                    Task {
                        await save()
                    }
                }
                .disabled(viewModel.isSaving || !draft.canSubmit)
            }

            Section {
                Button("Delete Record", role: .destructive) {
                    guard !viewModel.isSaving else { return }
                    showingDeleteConfirmation = true
                }
                .foregroundStyle(.red)
                .disabled(viewModel.isSaving)
            }
        }
        .navigationTitle(record.name)
        .navigationBarTitleDisplayMode(.inline)
        .overlay {
            if viewModel.isSaving {
                ProgressView()
                    .controlSize(.large)
            }
        }
        .interactiveDismissDisabled(viewModel.isSaving)
        .onChange(of: draft.type) { oldValue, newValue in
            guard oldValue != newValue else { return }
            draft.resetTypeSpecificFields()
        }
        .alert(deleteAlertTitle, isPresented: $showingDeleteConfirmation) {
            Button("Delete Record", role: .destructive) {
                Task {
                    await deleteRecord()
                }
            }
            Button("Cancel", role: .cancel) {}
        } message: {
            Text("This action cannot be undone.")
        }
        .alert("Request Failed", isPresented: mutationErrorBinding) {
            Button("OK", role: .cancel) {}
        } message: {
            Text(viewModel.mutationErrorMessage ?? "")
        }
    }

    private func save() async {
        guard !viewModel.isSaving else {
            return
        }

        do {
            try await viewModel.editRecord(for: domainName, recordID: record.id, draft: draft, client: client)
            dismiss()
        } catch is CancellationError {
            return
        } catch {
            return
        }
    }

    private func deleteRecord() async {
        guard !viewModel.isSaving else {
            return
        }

        do {
            try await viewModel.removeRecord(record, client: client)
            dismiss()
        } catch is CancellationError {
            return
        } catch {
            return
        }
    }

    private var mutationErrorBinding: Binding<Bool> {
        Binding(
            get: { viewModel.mutationErrorMessage != nil },
            set: { newValue in
                if !newValue {
                    viewModel.dismissMutationError()
                }
            }
        )
    }

    private var deleteAlertTitle: String {
        "Delete \(record.type) record \(record.name)?"
    }
}