connection updates

This commit is contained in:
Mark Gregory
2026-10-19 11:23:26 +01:00
parent bbc35ab4e3
commit 5aba461451
+103
View File
@@ -2962,6 +2962,8 @@ struct WorkbenchAdministrationView: View {
// Phase 25/26: bounded, in-session samples. No credentials or SQL persisted.
@State private var diagnosticSamples: [DiagnosticSample] = []
@State private var showingTrends = false
@State private var selectedLogEntry: DBSynLogDetail?
@State private var showingFullError = false
private var supportsTrends: Bool {
page == .slowQueries || page == .connectionStatistics ||
@@ -3077,6 +3079,7 @@ struct WorkbenchAdministrationView: View {
} description: {
Text(errorMessage)
} actions: {
Button("View Full Error…") { showingFullError = true }
Button("Retry") {
Task { await refresh() }
}
@@ -3237,6 +3240,12 @@ struct WorkbenchAdministrationView: View {
.sheet(isPresented: $showingTrends) {
WorkbenchDiagnosticTrendsView(page: page, samples: diagnosticSamples)
}
.sheet(item: $selectedLogEntry) { entry in
DBSynLogDetailSheet(title: "MySQL Server Log Entry", details: entry.text)
}
.sheet(isPresented: $showingFullError) {
DBSynLogDetailSheet(title: "MySQL Error Details", details: errorMessage ?? "No error available.")
}
.sheet(isPresented: $showingGrants) {
VStack(alignment: .leading, spacing: 12) {
Text("Grants: \(selectedAccount ?? "")")
@@ -3345,6 +3354,11 @@ struct WorkbenchAdministrationView: View {
Spacer()
if page == .serverLogs, let errorMessage {
Button("Full Error…") { showingFullError = true }
.help(errorMessage)
}
if page != .dashboard {
TextField("Filter results", text: $searchText)
.textFieldStyle(.roundedBorder)
@@ -3452,6 +3466,40 @@ struct WorkbenchAdministrationView: View {
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.accessibilityIdentifier("scrollable-dashboard-phase51")
case .serverLogs:
VStack(alignment: .leading, spacing: 0) {
HStack {
Text("Select an entry to view the complete log message and copy it.")
.font(.caption)
.foregroundStyle(.secondary)
Spacer()
Button("Copy All Logs") {
let all = filteredRows.map { logText(for: $0) }.joined(separator: "\n\n---\n\n")
NSPasteboard.general.clearContents()
NSPasteboard.general.setString(all, forType: .string)
}
.disabled(filteredRows.isEmpty)
}
.padding(12)
List(Array(filteredRows.enumerated()), id: \.offset) { _, row in
Button {
selectedLogEntry = DBSynLogDetail(text: logText(for: row))
} label: {
VStack(alignment: .leading, spacing: 5) {
Text(logValue("DATA", in: row))
.lineLimit(2)
.foregroundStyle(.primary)
.frame(maxWidth: .infinity, alignment: .leading)
Text([logValue("LOGGED", in: row), logValue("PRIO", in: row), logValue("ERROR_CODE", in: row)]
.filter { !$0.isEmpty }.joined(separator: " · "))
.font(.caption)
.foregroundStyle(.secondary)
}
.padding(.vertical, 4)
}
.buttonStyle(.plain)
}
}
case .serverCounters, .connectionStatistics, .innodbMetrics:
WorkbenchLiveMonitorScreen(
page: page,
@@ -3468,6 +3516,16 @@ struct WorkbenchAdministrationView: View {
}
}
private func logValue(_ name: String, in row: [String]) -> String {
guard let index = result.columns.firstIndex(where: { $0.caseInsensitiveCompare(name) == .orderedSame }),
index < row.count else { return "" }
return row[index]
}
private func logText(for row: [String]) -> String {
zip(result.columns, row).map { "\($0.0): \($0.1)" }.joined(separator: "\n")
}
private var footer: some View {
HStack {
if let lastUpdated {
@@ -7219,3 +7277,48 @@ private struct DBSynConnectionManager: View {
}
}
}
// MARK: - Copyable administration log details
private struct DBSynLogDetail: Identifiable {
let id = UUID()
let text: String
}
private struct DBSynLogDetailSheet: View {
let title: String
let details: String
@Environment(\.dismiss) private var dismiss
var body: some View {
VStack(alignment: .leading, spacing: 14) {
HStack {
Label(title, systemImage: "doc.text.magnifyingglass")
.font(.title2.bold())
Spacer()
Button("Copy Full Text") {
NSPasteboard.general.clearContents()
NSPasteboard.general.setString(details, forType: .string)
}
.keyboardShortcut("c", modifiers: [.command, .shift])
Button("Close") { dismiss() }
.keyboardShortcut(.cancelAction)
}
Text("Select text to copy, or use Copy Full Text for the complete error and metadata.")
.font(.caption)
.foregroundStyle(.secondary)
ScrollView([.vertical, .horizontal]) {
Text(details)
.font(.system(.body, design: .monospaced))
.textSelection(.enabled)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(12)
}
.background(Color(nsColor: .textBackgroundColor))
.overlay(RoundedRectangle(cornerRadius: 6).stroke(Color(nsColor: .separatorColor)))
}
.padding(20)
.frame(minWidth: 720, minHeight: 420)
}
}