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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Icon-only buttons announced as nothing by VoiceOver across the data grid, row inspector, editor find bar, filter bar, structure, dashboard and settings.
- Foreign key picker rows that could only be chosen with a mouse.
- No spoken sort direction on Query Plan columns.
- No columns, indexes or foreign keys listed for a MySQL server that answers `information_schema` with nothing or an error.
- Composite foreign key columns listed out of order on MariaDB.
- Export dialog listing no tables for a MySQL server behind a proxy, and failing to open at all on Kafka, Cassandra and Teradata.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct FindControls: View {
.padding(.horizontal, dynamicPadding)
}
.help("Previous Match")
.accessibilityLabel("Previous Match")
.disabled(viewModel.matchesEmpty)

Divider()
Expand All @@ -53,6 +54,7 @@ struct FindControls: View {
.padding(.horizontal, dynamicPadding)
}
.help("Next Match")
.accessibilityLabel("Next Match")
.disabled(viewModel.matchesEmpty)
}
.controlGroupStyle(PanelControlGroupStyle())
Expand All @@ -69,6 +71,7 @@ struct FindControls: View {
}
}
.help(condensed ? "Done" : "")
.accessibilityLabel("Done")
.padding(.horizontal, dynamicPadding)
}
.buttonStyle(PanelButtonStyle())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct ReplaceControls: View {
.opacity(shouldDisableSingle ? 0.33 : 1)
}
.help(condensed ? "Replace" : "")
.accessibilityLabel("Replace")
.disabled(shouldDisableSingle)
.frame(maxWidth: .infinity)

Expand All @@ -64,6 +65,7 @@ struct ReplaceControls: View {
.opacity(shouldDisableAll ? 0.33 : 1)
}
.help(condensed ? "Replace All" : "")
.accessibilityLabel("Replace All")
.disabled(shouldDisableAll)
.frame(maxWidth: .infinity)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ struct PanelTextField<LeadingAccessories: View, TrailingAccessories: View>: View
}
.buttonStyle(.icon(font: .system(size: 11, weight: .semibold), size: CGSize(width: 20, height: 20)))
.opacity(text.isEmpty ? 0 : 1)
.accessibilityLabel("Clear")
.disabled(text.isEmpty)
}
if let trailing = trailingAccessories {
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/AIChat/AIChatPanelView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ struct AIChatPanelView: View {
.menuStyle(.button)
.buttonStyle(.borderless)
.help(String(localized: "Choose AI provider and model"))
.accessibilityLabel(String(localized: "Choose AI provider and model"))
}
}

Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Components/DatabaseEndpointPicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ internal struct DatabaseEndpointPicker: View {
if current?.id == endpoint.id {
Image(systemName: "checkmark")
.foregroundStyle(.secondary)
.accessibilityLabel(String(localized: "Selected"))
}
}
.contentShape(.rect)
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Editor/QueryParameterPanelView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct QueryParameterPanelView: View {
}
.buttonStyle(.borderless)
.help(String(localized: "Close parameter panel"))
.accessibilityLabel(String(localized: "Close parameter panel"))
}
.padding(.horizontal, 12)
.padding(.vertical, 8)
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Export/ExportDialog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ struct ExportDialog: View {
.buttonStyle(.borderless)
.fixedSize()
.help(String(localized: "Saved selections"))
.accessibilityLabel(String(localized: "Saved selections"))
.popover(isPresented: $isNamingProfile, arrowEdge: .bottom) {
VStack(alignment: .leading, spacing: 10) {
Text("Name this selection")
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 @@ -173,6 +173,7 @@ struct FilterPanelView: View {
Image(systemName: "exclamationmark.triangle.fill")
.foregroundStyle(.yellow)
.help(String(localized: "Some columns in this preset don't exist in the current table"))
.accessibilityLabel(String(localized: "Some columns in this preset don't exist in the current table"))
}
}
}
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Filter/NestedFieldPathPicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ struct NestedFieldPathPicker: View {
.imageScale(.small)
.foregroundStyle(.secondary)
.help(String(localized: "Inside an array"))
.accessibilityLabel(String(localized: "Inside an array"))
}
Text(path.typeName)
.font(.caption)
Expand Down
3 changes: 3 additions & 0 deletions TablePro/Views/Inspector/InspectorFilterBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ struct InspectorFilterBar: View {
}
}
.labelsHidden()
.accessibilityLabel(String(localized: "Filter column"))
.frame(maxWidth: 180)
.onChange(of: clause.column) { _ in onChange() }

Expand All @@ -122,6 +123,7 @@ struct InspectorFilterBar: View {
}
}
.labelsHidden()
.accessibilityLabel(String(localized: "Filter operator"))
.frame(maxWidth: 160)
.onChange(of: clause.op) { _ in onChange() }

Expand All @@ -145,6 +147,7 @@ struct InspectorFilterBar: View {
}
.buttonStyle(.plain)
.help(String(localized: "Remove filter"))
.accessibilityLabel(String(localized: "Remove filter"))
}
}

Expand Down
19 changes: 19 additions & 0 deletions TablePro/Views/QueryPlan/QueryPlanOutlineCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ final class QueryPlanOutlineCoordinator: NSObject, NSOutlineViewDataSource, NSOu
// The rebuilt tree is in parse order, so a sort indicator left over from the previous
// plan would advertise an order the rows are not in.
outlineView?.sortDescriptors = []
publishSortDirection()
outlineView?.reloadData()
expandAll()
selectRootRow()
Expand Down Expand Up @@ -134,11 +135,29 @@ final class QueryPlanOutlineCoordinator: NSObject, NSOutlineViewDataSource, NSOu
}

func outlineView(_ outlineView: NSOutlineView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) {
publishSortDirection()
guard applyCurrentSort() else { return }
outlineView.reloadData()
expandAll()
}

/// `sortDescriptors` reaches no accessibility client, measured, so the sorted column is only
/// announced when its header cell is told directly. Every column here is click-sortable, so
/// without this a VoiceOver user cannot tell which one is sorted or which way.
internal func publishSortDirection() {
guard let outlineView else { return }
let sorted = outlineView.sortDescriptors.first
for column in outlineView.tableColumns {
let direction: NSAccessibilitySortDirection
if let sorted, sorted.key == column.identifier.rawValue {
direction = sorted.ascending ? .ascending : .descending
} else {
direction = .unknown
}
column.headerCell.setAccessibilitySortDirection(direction)
}
}

/// Reorders the tree by whatever the header currently advertises, keeping the selection. False
/// when there is nothing to sort by, which leaves the rows in parse order.
@discardableResult
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/QueryPlan/QueryPlanResultView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ struct QueryPlanResultView: View {
.buttonStyle(.bordered)
.controlSize(.small)
.help(String(localized: "Copy EXPLAIN output to clipboard"))
.accessibilityLabel(String(localized: "Copy EXPLAIN output to clipboard"))
}
.padding(.horizontal, 12)
.padding(.vertical, 8)
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Results/ArrayValueEditorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ struct ArrayValueEditorView: View {
Image(systemName: "exclamationmark.triangle")
.foregroundStyle(.orange)
.help(Text("This value is not one of the type's current labels"))
.accessibilityLabel(Text("This value is not one of the type's current labels"))
}
}

Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Results/CellImageViewer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ internal struct CellImageViewer<Source: View>: View {
}
.buttonStyle(.borderless)
.help(String(localized: "Open in Window"))
.accessibilityLabel(String(localized: "Open in Window"))
}
}
.padding(.horizontal, 10)
Expand Down
2 changes: 2 additions & 0 deletions TablePro/Views/Results/ForeignKeyPickerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ struct ForeignKeyPickerView: View {
row(for: entry)
.contentShape(Rectangle())
.onTapGesture { commit(entry) }
.accessibilityAddTraits(.isButton)
.accessibilityAction { commit(entry) }
}
.listStyle(.plain)
.scrollContentBackground(.hidden)
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Results/JSONViewerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ internal struct JSONViewerView: View {
}
.buttonStyle(.borderless)
.help(String(localized: "Open in Window"))
.accessibilityLabel(String(localized: "Open in Window"))
}
}
.padding(.horizontal, 10)
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Results/PhpViewerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ internal struct PhpViewerView: View {
}
.buttonStyle(.borderless)
.help(String(localized: "Open in Window"))
.accessibilityLabel(String(localized: "Open in Window"))
}
}
.padding(.horizontal, 10)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ internal struct JsonEditorView: View {
}
.buttonStyle(.borderless)
.help(String(localized: "Open in Window"))
.accessibilityLabel(String(localized: "Open in Window"))
}
}
.padding(4)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ internal struct MultiLineEditorView: View {
}
.buttonStyle(.borderless)
.help(String(localized: "Open in Window"))
.accessibilityLabel(String(localized: "Open in Window"))
.padding(4)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ struct JSONRowInspectorView: View {
.menuIndicator(.hidden)
.fixedSize()
.help(String(localized: "JSON view options"))
.accessibilityLabel(String(localized: "JSON view options"))
}

// MARK: - Tree
Expand Down
2 changes: 2 additions & 0 deletions TablePro/Views/ServerDashboard/DashboardToolbarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct DashboardToolbarView: View {
}
.buttonStyle(.borderless)
.help(viewModel.isPaused ? String(localized: "Resume") : String(localized: "Pause"))
.accessibilityLabel(viewModel.isPaused ? String(localized: "Resume") : String(localized: "Pause"))
.disabled(viewModel.refreshInterval == .off)

Button {
Expand All @@ -42,6 +43,7 @@ struct DashboardToolbarView: View {
}
.buttonStyle(.borderless)
.help(String(localized: "Refresh Now"))
.accessibilityLabel(String(localized: "Refresh Now"))
.disabled(viewModel.isRefreshing)

Spacer()
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Settings/AIProviderDetailSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ struct AIProviderDetailSheet: View {
}
.buttonStyle(.borderless)
.help(String(localized: "Copy install command"))
.accessibilityLabel(String(localized: "Copy install command"))
} label: {
Text(CursorAgentCLI.installCommand)
.font(.system(.body, design: .monospaced))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ internal struct ThemeEditorColorsSection: View {
}
.buttonStyle(.borderless)
.help(String(localized: "Reset to System Default"))
.accessibilityLabel(String(localized: "Reset to System Default"))
}
}
}
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/Settings/LinkedFoldersSection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ struct LinkedFoldersSection: View {
.toggleStyle(.switch)
.controlSize(.mini)
.labelsHidden()
.accessibilityLabel(folder.name)

VStack(alignment: .leading, spacing: 1) {
Text(folder.name)
Expand Down
2 changes: 2 additions & 0 deletions TablePro/Views/Structure/CreateTableView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,15 @@ struct CreateTableView: View {
.frame(width: 24, height: 24)
}
.help(String(localized: "Add Row"))
.accessibilityLabel(String(localized: "Add Row"))
.disabled(!isGridTab)

Button(action: { gridDelegate.dataGridDeleteRows(selectedRows) }) {
Image(systemName: "minus")
.frame(width: 24, height: 24)
}
.help(String(localized: "Delete Selected"))
.accessibilityLabel(String(localized: "Delete Selected"))
.disabled(!isGridTab || selectedRows.isEmpty)

issueMessage(issues)
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/UsersRoles/PrivilegeChecklistView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ struct PrivilegeChecklistView: View {
.fixedSize()
.disabled(viewModel.privilegeSections.isEmpty)
.help(String(localized: "Bulk actions"))
.accessibilityLabel(String(localized: "Bulk actions"))
}

// MARK: - Content
Expand Down
1 change: 1 addition & 0 deletions TablePro/Views/UsersRoles/PrivilegeScopeRowView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct ScopeSummaryView: View {
Image(systemName: "arrow.up.forward.square")
.foregroundStyle(.secondary)
.help(String(localized: "Can grant these privileges to others."))
.accessibilityLabel(String(localized: "Can grant these privileges to others."))
}
}

Expand Down
Loading
Loading