Improved progress display

Previously, the progress bar updated only after completing an entire table.

For large tables such as LIBARC, this could make the application appear to have stopped responding.

Phase 10 updates the interface while rows are being exported.
This commit is contained in:
Mark Gregory
2026-10-17 11:54:29 +01:00
parent e1a9b4037e
commit d441aea02c
8 changed files with 33 additions and 59 deletions
+22 -32
View File
@@ -4155,7 +4155,7 @@ private struct WorkbenchInlinePerformanceDashboard: View {
Text("\(samples.count) samples · refreshes every 5 seconds")
.font(.caption).foregroundStyle(.secondary)
}
LazyVGrid(columns: [GridItem(.adaptive(minimum: 360), spacing: 14)], spacing: 12) {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 410), spacing: 16)], spacing: 12) {
panel("Queries per second", metric: "Queries", rate: true, tint: .blue)
panel("Active connections", metric: "Threads_connected", rate: false, tint: .teal)
panel("Running threads", metric: "Threads_running", rate: false, tint: .orange)
@@ -4204,44 +4204,34 @@ private struct WorkbenchServerCountersScreen: View {
category == "All" ? rows : rows.filter { $0.count >= 2 && group($0[0]) == category }
}
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 18) {
HStack {
Label("Server overview", systemImage: "server.rack").font(.title3.bold())
Spacer()
Text("Live MySQL status · 5-second refresh").font(.caption).foregroundStyle(.secondary)
}
LazyVGrid(columns: [GridItem(.adaptive(minimum: 155), spacing: 10)], spacing: 10) {
overview("Queries", metric: "Queries", tint: .blue)
overview("Connected", metric: "Threads_connected", tint: .teal)
overview("Running", metric: "Threads_running", tint: .orange)
overview("Slow queries", metric: "Slow_queries", tint: .red)
overview("Received", metric: "Bytes_received", tint: .purple)
overview("Sent", metric: "Bytes_sent", tint: .green)
}
HStack {
Label("Performance trends", systemImage: "chart.xyaxis.line").font(.title3.bold())
Spacer()
Text("\(samples.count) samples").font(.caption).foregroundStyle(.secondary)
}
ScrollView(.vertical) {
VStack(alignment: .leading, spacing: 20) {
// Graphs are the primary content, never hidden below summary cards.
WorkbenchCounterCharts(page: .serverCounters, samples: samples)
.frame(maxWidth: .infinity, alignment: .leading)
Divider()
HStack {
Label("All server counters", systemImage: "list.bullet.rectangle").font(.title3.bold())
Label("All MySQL server counters", systemImage: "list.bullet.rectangle")
.font(.title3.bold())
Spacer()
Text("\(visibleRows.count) of \(rows.count)").font(.caption).foregroundStyle(.secondary)
Text("\(visibleRows.count) of \(rows.count) counters")
.font(.caption).foregroundStyle(.secondary)
}
Picker("Counter category", selection: $category) {
ForEach(categories, id: \.self) { Text($0).tag($0) }
}
.pickerStyle(.segmented)
WorkbenchColouredCounterTable(columns: ["Variable_name", "Value"], rows: visibleRows)
.frame(minHeight: 360, idealHeight: 600)
Text("Colours identify counter families, not server health. Error totals are cumulative; a nonzero value does not by itself indicate a current fault.")
.frame(height: 450)
Text("Colours identify counter families, not server health. Error totals are cumulative; nonzero values do not necessarily indicate a current fault.")
.font(.caption).foregroundStyle(.secondary)
}
.padding(18)
.padding(20)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}
// MARK: - Phase 29: Inline coloured counter graphs
@@ -4449,15 +4439,15 @@ private struct WorkbenchCounterCharts: View {
.foregroundStyle(tint).lineStyle(StrokeStyle(lineWidth: 2.5))
}
.chartYAxis { AxisMarks(position: .leading) }
.frame(height: 115)
.frame(height: 205)
if values.isEmpty {
Text("Waiting for samples").font(.caption2).foregroundStyle(.secondary)
}
}
.padding(14)
.padding(16)
.frame(maxWidth: .infinity, alignment: .leading)
.background(tint.opacity(0.08))
.clipShape(RoundedRectangle(cornerRadius: 12))
.background(Color(nsColor: .controlBackgroundColor), in: RoundedRectangle(cornerRadius: 12))
.overlay(RoundedRectangle(cornerRadius: 12).stroke(tint.opacity(0.35), lineWidth: 1))
}
var body: some View {
@@ -4469,10 +4459,10 @@ private struct WorkbenchCounterCharts: View {
Text("\(samples.count) samples · 5-second refresh")
.font(.caption).foregroundStyle(.secondary)
}
LazyVGrid(columns: [GridItem(.adaptive(minimum: 360), spacing: 14)], spacing: 12) {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 410), spacing: 16)], spacing: 12) {
ForEach(metrics, id: \.self) { metric in graph(metric) }
}
Text("Graphs use real MySQL samples. Cumulative counters display change per second; thread counts show current values. Rates appear after two successful samples.")
Text("Live MySQL data • refreshes every five seconds. Rates appear after two successful samples; thread counts show current values.")
.font(.caption).foregroundStyle(.secondary)
}
}