Skip to content

Commit 005c74f

Browse files
committed
fix: JSON viewer bugs — NULL data loss, tree expand, undo, display issues
1 parent 2bce72d commit 005c74f

7 files changed

Lines changed: 68 additions & 10 deletions

File tree

TablePro/Models/UI/JSONTreeNode.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,14 @@ internal enum JSONTreeParser {
110110
}
111111

112112
if let str = value as? String {
113+
let escaped = str.replacingOccurrences(of: "\"", with: "\\\"")
113114
let display: String
114-
if (str as NSString).length > 80 {
115-
display = "\"\(str.prefix(80))...\""
115+
let nsLen = (escaped as NSString).length
116+
if nsLen > 80 {
117+
let truncated = (escaped as NSString).substring(to: 80)
118+
display = "\"\(truncated)...\""
116119
} else {
117-
display = "\"\(str)\""
120+
display = "\"\(escaped)\""
118121
}
119122
return JSONTreeNode(
120123
key: key, keyPath: keyPath, valueType: .string,

TablePro/Resources/Localizable.xcstrings

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@
9191
}
9292
}
9393
}
94+
},
95+
":" : {
96+
9497
},
9598
".%@" : {
9699
"localizations" : {
@@ -7578,6 +7581,9 @@
75787581
}
75797582
}
75807583
}
7584+
},
7585+
"Collapse All" : {
7586+
75817587
},
75827588
"Collation" : {
75837589
"localizations" : {
@@ -9285,6 +9291,12 @@
92859291
}
92869292
}
92879293
}
9294+
},
9295+
"Copy Key" : {
9296+
9297+
},
9298+
"Copy Key Path" : {
9299+
92889300
},
92899301
"Copy Name" : {
92909302
"localizations" : {
@@ -11364,6 +11376,9 @@
1136411376
}
1136511377
}
1136611378
}
11379+
},
11380+
"Default view:" : {
11381+
1136711382
},
1136811383
"Default:" : {
1136911384
"extractionState" : "stale",
@@ -14220,6 +14235,9 @@
1422014235
}
1422114236
}
1422214237
}
14238+
},
14239+
"Expand All" : {
14240+
1422314241
},
1422414242
"Expired" : {
1422514243
"localizations" : {
@@ -16069,6 +16087,9 @@
1606916087
},
1607016088
"Fetch All Rows" : {
1607116089

16090+
},
16091+
"Fields" : {
16092+
1607216093
},
1607316094
"FIELDS" : {
1607416095
"localizations" : {
@@ -16304,6 +16325,9 @@
1630416325
}
1630516326
}
1630616327
}
16328+
},
16329+
"Filter keys or values..." : {
16330+
1630716331
},
1630816332
"Filter logic mode" : {
1630916333
"localizations" : {
@@ -16799,6 +16823,9 @@
1679916823
}
1680016824
}
1680116825
}
16826+
},
16827+
"Format JSON" : {
16828+
1680216829
},
1680316830
"Format Query" : {
1680416831

@@ -19668,6 +19695,12 @@
1966819695
}
1966919696
}
1967019697
}
19698+
},
19699+
"JSON Too Large" : {
19700+
19701+
},
19702+
"JSON Viewer" : {
19703+
1967119704
},
1967219705
"Jump Hosts" : {
1967319706
"localizations" : {
@@ -25048,6 +25081,9 @@
2504825081
},
2504925082
"Open in Editor" : {
2505025083

25084+
},
25085+
"Open JSON Viewer" : {
25086+
2505125087
},
2505225088
"Open MQL Editor" : {
2505325089
"extractionState" : "stale",
@@ -35772,6 +35808,9 @@
3577235808
}
3577335809
}
3577435810
}
35811+
},
35812+
"The text could not be parsed as JSON. Use text mode to view or edit." : {
35813+
3577535814
},
3577635815
"The text is not valid JSON. Save anyway?" : {
3577735816
"localizations" : {
@@ -36066,6 +36105,9 @@
3606636105
}
3606736106
}
3606836107
}
36108+
},
36109+
"This JSON document is too large for tree view. Use text mode instead." : {
36110+
3606936111
},
3607036112
"This keyword is already in use" : {
3607136113
"localizations" : {

TablePro/Views/Results/JSONEditorContentView.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ struct JSONEditorContentView: View {
2929
isEditable: true,
3030
onDismiss: onDismiss,
3131
onCommit: { newValue in
32-
if newValue != initialValue {
32+
let effective = newValue.isEmpty ? nil : newValue
33+
if effective != initialValue {
3334
onCommit(newValue)
3435
}
3536
}

TablePro/Views/Results/JSONSyntaxTextView.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,16 @@ internal struct JSONSyntaxTextView: NSViewRepresentable {
6060
func updateNSView(_ scrollView: NSScrollView, context: Context) {
6161
guard let textView = scrollView.documentView as? NSTextView else { return }
6262
if textView.string != text, !context.coordinator.isUpdating {
63-
textView.string = text
63+
let fullRange = NSRange(location: 0, length: (textView.string as NSString).length)
64+
if isEditable,
65+
textView.shouldChangeText(in: fullRange, replacementString: text) {
66+
context.coordinator.isUpdating = true
67+
textView.textStorage?.replaceCharacters(in: fullRange, with: text)
68+
textView.didChangeText()
69+
context.coordinator.isUpdating = false
70+
} else {
71+
textView.string = text
72+
}
6473
Self.applyHighlighting(to: textView)
6574
}
6675
}

TablePro/Views/Results/JSONTreeView.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ internal struct JSONTreeView: View {
8383

8484
private func expandMatchingNodes() {
8585
if searchText.isEmpty {
86-
expandedNodeIDs = [rootNode.id]
86+
expandedNodeIDs.removeAll()
87+
expandRootLevel()
8788
return
8889
}
8990
expandedNodeIDs.formUnion(collectMatchingContainerIDs(filteredRootNodes))
@@ -109,7 +110,9 @@ internal struct JSONTreeView: View {
109110
}
110111

111112
private func expandRootLevel() {
112-
expandedNodeIDs.insert(rootNode.id)
113+
for child in rootNode.children where !child.children.isEmpty {
114+
expandedNodeIDs.insert(child.id)
115+
}
113116
}
114117

115118
private func collectAllContainerIDs(_ node: JSONTreeNode) -> Set<UUID> {

TablePro/Views/Results/JSONViewerView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ internal struct JSONViewerView: View {
6363
Text("Tree").tag(JSONViewMode.tree)
6464
}
6565
.pickerStyle(.segmented)
66-
.frame(width: 140)
66+
.fixedSize()
6767
Spacer()
6868
if viewMode == .text && isEditable {
6969
Button {
@@ -183,7 +183,7 @@ internal struct JSONViewerView: View {
183183
let jsonObject = try? JSONSerialization.jsonObject(with: data),
184184
let compactData = try? JSONSerialization.data(
185185
withJSONObject: jsonObject,
186-
options: [.withoutEscapingSlashes]
186+
options: [.sortedKeys, .withoutEscapingSlashes]
187187
),
188188
let compactString = String(data: compactData, encoding: .utf8) else {
189189
return nil

TablePro/Views/RightSidebar/FieldEditors/JsonEditorView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ internal struct JsonEditorView: View {
1414
.frame(minHeight: context.isReadOnly ? 60 : 80, maxHeight: 120)
1515
.clipShape(RoundedRectangle(cornerRadius: 5))
1616
.overlay(RoundedRectangle(cornerRadius: 5).strokeBorder(Color(nsColor: .separatorColor)))
17-
.overlay(alignment: .topTrailing) {
17+
.overlay(alignment: .bottomTrailing) {
1818
if let onExpand {
1919
Button(action: onExpand) {
2020
Image(systemName: "arrow.up.left.and.arrow.down.right")

0 commit comments

Comments
 (0)