Skip to content

Commit 08bd721

Browse files
committed
feat(import): add select-all toggles and mapping validation to the JSON import sheet
1 parent d51e289 commit 08bd721

1 file changed

Lines changed: 56 additions & 14 deletions

File tree

TablePro/Views/Import/JSONImportSheet.swift

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,12 @@ struct JSONImportSheet: View {
188188
HStack {
189189
Button("Cancel") { isPresented = false }
190190
.keyboardShortcut(.cancelAction)
191+
if let message = validationMessage {
192+
Text(message)
193+
.font(.caption)
194+
.foregroundStyle(.red)
195+
.lineLimit(2)
196+
}
191197
Spacer()
192198
Button("Import") { performImport() }
193199
.buttonStyle(.borderedProminent)
@@ -233,12 +239,12 @@ struct JSONImportSheet: View {
233239
ScrollView {
234240
Grid(alignment: .leading, horizontalSpacing: 12, verticalSpacing: 6) {
235241
GridRow {
236-
Text("Import")
237-
Text("JSON field")
238-
Text("Column")
242+
Toggle("", isOn: allMappingsIncluded)
243+
.labelsHidden()
244+
.help(String(localized: "Import all fields"))
245+
Text("JSON field").font(.caption).foregroundStyle(.secondary)
246+
Text("Column").font(.caption).foregroundStyle(.secondary)
239247
}
240-
.font(.caption)
241-
.foregroundStyle(.secondary)
242248
Divider().gridCellColumns(3)
243249

244250
ForEach(mappings) { row in
@@ -271,15 +277,15 @@ struct JSONImportSheet: View {
271277
ScrollView {
272278
Grid(alignment: .leading, horizontalSpacing: 10, verticalSpacing: 6) {
273279
GridRow {
274-
Text("Create")
275-
Text("Column")
276-
Text("Type")
277-
Text("Key")
278-
Text("Null")
279-
Text("Default")
280+
Toggle("", isOn: allColumnsIncluded)
281+
.labelsHidden()
282+
.help(String(localized: "Create all columns"))
283+
Text("Column").font(.caption).foregroundStyle(.secondary)
284+
Text("Type").font(.caption).foregroundStyle(.secondary)
285+
Text("Key").font(.caption).foregroundStyle(.secondary)
286+
Text("Null").font(.caption).foregroundStyle(.secondary)
287+
Text("Default").font(.caption).foregroundStyle(.secondary)
280288
}
281-
.font(.caption)
282-
.foregroundStyle(.secondary)
283289
Divider().gridCellColumns(6)
284290

285291
ForEach(newColumns) { row in
@@ -327,6 +333,42 @@ struct JSONImportSheet: View {
327333
return $newColumns[index]
328334
}
329335

336+
private var allMappingsIncluded: Binding<Bool> {
337+
Binding(
338+
get: { !mappings.isEmpty && mappings.allSatisfy(\.include) },
339+
set: { value in for index in mappings.indices { mappings[index].include = value } }
340+
)
341+
}
342+
343+
private var allColumnsIncluded: Binding<Bool> {
344+
Binding(
345+
get: { !newColumns.isEmpty && newColumns.allSatisfy(\.include) },
346+
set: { value in for index in newColumns.indices { newColumns[index].include = value } }
347+
)
348+
}
349+
350+
private var validationMessage: String? {
351+
switch destination {
352+
case .existingTable:
353+
let columns = mappings.filter { $0.include }.compactMap { $0.targetColumn?.lowercased() }
354+
if Set(columns).count != columns.count {
355+
return String(localized: "Each column can be mapped from only one field.")
356+
}
357+
return nil
358+
case .newTable:
359+
let names = newColumns
360+
.filter { $0.include }
361+
.map { $0.name.trimmingCharacters(in: .whitespaces).lowercased() }
362+
if names.contains(where: \.isEmpty) {
363+
return String(localized: "Every included column needs a name.")
364+
}
365+
if Set(names).count != names.count {
366+
return String(localized: "Column names must be unique.")
367+
}
368+
return nil
369+
}
370+
}
371+
330372
private var dialectTypes: [String] {
331373
PluginManager.shared.columnTypesByCategory(for: connection.type)
332374
.values
@@ -356,7 +398,7 @@ struct JSONImportSheet: View {
356398
}
357399

358400
private var canImport: Bool {
359-
guard !(importService?.state.isImporting ?? false) else { return false }
401+
guard !(importService?.state.isImporting ?? false), validationMessage == nil else { return false }
360402
switch destination {
361403
case .existingTable:
362404
return selectedTargetTable != nil && mappings.contains { $0.include && $0.targetColumn != nil }

0 commit comments

Comments
 (0)