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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
import SwiftUI
struct GlueEditView: View {
let domainName: String
let existingRecord: GlueRecord?
@ObservedObject var viewModel: DomainViewModel
let client: NjallaClient
@Environment(\.dismiss) private var dismiss
@State private var name: String
@State private var address4: String
@State private var address6: String
@State private var localErrorMessage: String?
init(domainName: String, existingRecord: GlueRecord?, viewModel: DomainViewModel, client: NjallaClient) {
self.domainName = domainName
self.existingRecord = existingRecord
self.viewModel = viewModel
self.client = client
_name = State(initialValue: existingRecord?.name ?? "")
_address4 = State(initialValue: existingRecord?.address4 ?? "")
_address6 = State(initialValue: existingRecord?.address6 ?? "")
}
var body: some View {
Form {
Section("Record") {
TextField("Name", text: $name)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
.disabled(existingRecord != nil)
TextField("IPv4", text: $address4)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
TextField("IPv6", text: $address6)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
}
Section {
Button("Save") {
Task {
await save()
}
}
.disabled(viewModel.isSaving)
}
}
.navigationTitle(existingRecord == nil ? "Add Glue" : "Edit Glue")
.navigationBarTitleDisplayMode(.inline)
.overlay {
if viewModel.isSaving {
ProgressView()
.controlSize(.large)
}
}
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel", role: .cancel) {
dismiss()
}
.disabled(viewModel.isSaving)
}
}
.alert("Invalid Glue Data", isPresented: localErrorBinding) {
Button("OK", role: .cancel) {}
} message: {
Text(localErrorMessage ?? "")
}
.alert("Request Failed", isPresented: mutationErrorBinding) {
Button("OK", role: .cancel) {}
} message: {
Text(viewModel.mutationErrorMessage ?? "")
}
}
private func save() async {
let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedAddress4 = address4.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedAddress6 = address6.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmedName.isEmpty else {
localErrorMessage = "Glue record name is required."
return
}
guard !trimmedAddress4.isEmpty || !trimmedAddress6.isEmpty else {
localErrorMessage = "Provide at least one address (IPv4 or IPv6)."
return
}
do {
if existingRecord == nil {
try await viewModel.addGlue(
for: domainName,
name: trimmedName,
address4: trimmedAddress4.isEmpty ? nil : trimmedAddress4,
address6: trimmedAddress6.isEmpty ? nil : trimmedAddress6,
client: client
)
} else {
try await viewModel.editGlue(
for: domainName,
name: trimmedName,
address4: trimmedAddress4.isEmpty ? nil : trimmedAddress4,
address6: trimmedAddress6.isEmpty ? nil : trimmedAddress6,
client: client
)
}
dismiss()
} catch {
return
}
}
private var localErrorBinding: Binding<Bool> {
Binding(
get: { localErrorMessage != nil },
set: { newValue in
if !newValue {
localErrorMessage = nil
}
}
)
}
private var mutationErrorBinding: Binding<Bool> {
Binding(
get: { viewModel.mutationErrorMessage != nil },
set: { newValue in
if !newValue {
viewModel.dismissMutationError()
}
}
)
}
}
|