Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Terminal PTY writes retry on `EINTR` instead of treating any non-positive return as "we're done". A signal mid-write previously truncated the input the user typed; the loop would exit silently and the keystrokes were partially sent. The new path retries on `EINTR`, logs the byte position and errno on any other non-recoverable failure, and reports a return value of zero distinctly so the cause is visible in Console.
- MCP HTTP transport no longer writes an empty body when JSON encoding of the response envelope fails. Five sites in `MCPInboundExchange` and `MCPHttpRequestRouter` previously fell back to `Data()`, sending zero bytes to the client which then saw a protocol violation and either disconnected or hung. The encode-failure paths now log and substitute a static `{"jsonrpc":"2.0","id":null,"error":{"code":-32603,"message":"internal_error"}}` envelope; the pairing-exchange success path falls back to `internalServerError` with a small JSON error body.
- Closing the last window for a connection no longer flashes "Connection lost" and clears that session's cached schema. The health monitor's reconnect loop previously transitioned to `.failed` when its task was cancelled (clean teardown), and the session-level observer treated `.failed` as a real error: it overwrote `session.status` with the lost-connection alert and called `clearCachedData()`. The `.failed` state was never reachable through any non-cancellation path, so it has been removed from `HealthState` along with the orphaned `resetAfterManualReconnect` reset method that only existed to reset from it. Cancellation now logs cleanly and returns without touching session state.
- Smart-quote, dash, and text substitution no longer corrupt user input in cell editors and filter inputs. Six SwiftUI `TextField` sites (single-line cell editor, multi-line cell editor, blob hex editor, filter row second value, filter preset name, create-table table name) gain `.autocorrectionDisabled(true)`, and the AppKit `FilterValueTextField` now subclasses `NSTextField` to disable all four substitution flags on the live field editor in `becomeFirstResponder()`. Previously the macOS field editor turned typed straight quotes into curly quotes and `--` into an em-dash, silently corrupting filter operands, identifiers, and edited cell values.
- Connecting one window no longer triggers `fetchTables()` in every other window for an unrelated connection. Three subscribers to `AppEvents.databaseDidConnect` (`MainContentCommandActions`, `MainContentCoordinator`'s plugin-driver retry, and `ERDiagramViewModel.waitForConnection`) discarded the `connectionId` payload that was already on the event and acted on their own connection. With three windows open against three different databases, opening a fourth caused nine `fetchTables()` calls; if the existing remotes were slow, every window stalled until the new connection's broadcast was processed. Subscribers now compare the payload's `connectionId` against their own and skip otherwise. The ER diagram view also stops resuming `waitForConnection` when an unrelated database connects, which previously made the diagram fail with "No database connection" instead of waiting for its own driver.
- Result-grid cells on rows marked for deletion keep their dropdown / date / JSON / blob chevron visible at reduced opacity instead of hiding it, so the cell type is still legible while clearly inactive. Click on the dimmed chevron is a no-op; FK arrow navigation is unchanged. Matches the macOS HIG "disabled appearance" guideline.
- Foreign key navigation from a table with unsaved edits opens the referenced table in a new window tab to preserve the edit buffer. Closing that new tab no longer wipes the original tab's data grid. Previously the new tab's teardown broadcast a connection-scoped event that other coordinators on the same connection received, causing them to release their cell data.
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Filter/FilterPanelView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ struct FilterPanelView: View {
.contentShape(Rectangle())
.alert(String(localized: "Save Filter Preset"), isPresented: $showSavePresetAlert) {
TextField(String(localized: "Preset Name"), text: $newPresetName)
.autocorrectionDisabled(true)
Button("Cancel", role: .cancel) {}
Button("Save") {
guard !newPresetName.isEmpty else { return }
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Filter/FilterRowView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ struct FilterRowView: View {
.textFieldStyle(.roundedBorder)
.controlSize(.small)
.font(.callout)
.autocorrectionDisabled(true)
.frame(minWidth: 80)
.accessibilityLabel(String(localized: "Second filter value"))
.onSubmit { onSubmit() }
Expand Down
15 changes: 14 additions & 1 deletion TablePro/Views/Filter/FilterValueTextField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct FilterValueTextField: NSViewRepresentable {
}

func makeNSView(context: Context) -> NSTextField {
let textField = NSTextField()
let textField = SubstitutionDisabledTextField()
textField.bezelStyle = .roundedBezel
textField.controlSize = .small
textField.font = .systemFont(ofSize: 12)
Expand Down Expand Up @@ -291,6 +291,19 @@ struct FilterValueTextField: NSViewRepresentable {
}
}

private final class SubstitutionDisabledTextField: NSTextField {
override func becomeFirstResponder() -> Bool {
let result = super.becomeFirstResponder()
if result, let editor = currentEditor() as? NSTextView {
editor.isAutomaticQuoteSubstitutionEnabled = false
editor.isAutomaticDashSubstitutionEnabled = false
editor.isAutomaticTextReplacementEnabled = false
editor.isAutomaticSpellingCorrectionEnabled = false
}
return result
}
}

@MainActor
private final class SuggestionState: ObservableObject {
@Published var items: [String] = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ internal struct BlobHexEditorView: View {
.textFieldStyle(.roundedBorder)
.font(.system(.caption2, design: .monospaced))
.lineLimit(3...8)
.autocorrectionDisabled(true)
.focused($isFocused)
.onAppear {
hexEditText = BlobFormattingService.shared.format(context.value.wrappedValue, for: .edit) ?? ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal struct MultiLineEditorView: View {
.textFieldStyle(.roundedBorder)
.font(.subheadline)
.lineLimit(3...6)
.autocorrectionDisabled(true)
.focused($isFocused)
.disabled(context.isReadOnly)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ internal struct SingleLineEditorView: View {
TextField(context.placeholderText, text: context.value)
.textFieldStyle(.roundedBorder)
.font(.subheadline)
.autocorrectionDisabled(true)
.focused($isFocused)
.disabled(context.isReadOnly)
}
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Structure/CreateTableView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ struct CreateTableView: View {

TextField("Enter table name", text: $tableName)
.textFieldStyle(.roundedBorder)
.autocorrectionDisabled(true)
.frame(maxWidth: 300)

if showMySQLOptions {
Expand Down
Loading