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:
@@ -2573,9 +2573,9 @@ struct WorkbenchAdministrationView: View {
|
||||
|
||||
ScrollView(.vertical) {
|
||||
VStack(alignment: .leading, spacing: 14) {
|
||||
Label("Server overview", systemImage: "server.rack")
|
||||
Label("Server overview · Live graphs", systemImage: "chart.xyaxis.line")
|
||||
.font(.title3.bold())
|
||||
WorkbenchServerOverview(rows: filteredRows)
|
||||
WorkbenchServerOverview(rows: filteredRows, samples: diagnosticSamples)
|
||||
if page == .serverStatus {
|
||||
Divider()
|
||||
HStack {
|
||||
@@ -4214,22 +4214,68 @@ private struct WorkbenchInlinePerformanceDashboard: View {
|
||||
// the counter ScrollView, so scrolling hundreds of counters cannot hide charts.
|
||||
private struct WorkbenchServerOverview: View {
|
||||
let rows: [[String]]
|
||||
private let names = ["Uptime", "Threads_connected", "Threads_running", "Queries", "Slow_queries", "Bytes_received", "Bytes_sent", "Connections"]
|
||||
let samples: [DiagnosticSample]
|
||||
|
||||
private let names = [
|
||||
"Uptime", "Threads_connected", "Threads_running", "Queries",
|
||||
"Slow_queries", "Bytes_received", "Bytes_sent", "Connections"
|
||||
]
|
||||
|
||||
private struct OverviewPoint: Identifiable {
|
||||
let id: Int
|
||||
let time: Date
|
||||
let value: Double
|
||||
}
|
||||
|
||||
private func points(for name: String) -> [OverviewPoint] {
|
||||
samples.enumerated().compactMap { index, sample in
|
||||
guard let row = sample.rows.first(where: {
|
||||
$0.count > 1 && $0[0].caseInsensitiveCompare(name) == .orderedSame
|
||||
}), let value = Double(row[1]), value.isFinite else { return nil }
|
||||
return OverviewPoint(id: index, time: sample.at, value: value)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
LazyVGrid(columns: [GridItem(.adaptive(minimum: 175), spacing: 12)], spacing: 12) {
|
||||
LazyVGrid(columns: [GridItem(.adaptive(minimum: 260), spacing: 14)], spacing: 14) {
|
||||
ForEach(names, id: \.self) { name in
|
||||
let raw = rows.first(where: { $0.count >= 2 && $0[0].caseInsensitiveCompare(name) == .orderedSame })?.last ?? "—"
|
||||
let raw = rows.first(where: {
|
||||
$0.count >= 2 && $0[0].caseInsensitiveCompare(name) == .orderedSame
|
||||
})?.last ?? "—"
|
||||
let tint = WorkbenchCounterCharts.tint(for: name)
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(name.replacingOccurrences(of: "_", with: " "))
|
||||
.font(.caption).foregroundStyle(.secondary)
|
||||
Text(WorkbenchCounterCharts.displayValue(raw, for: name))
|
||||
.font(.title3.bold().monospacedDigit())
|
||||
.foregroundStyle(tint)
|
||||
let series = points(for: name)
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
HStack(alignment: .firstTextBaseline) {
|
||||
Text(name.replacingOccurrences(of: "_", with: " "))
|
||||
.font(.subheadline.weight(.semibold))
|
||||
Spacer(minLength: 8)
|
||||
Text(WorkbenchCounterCharts.displayValue(raw, for: name))
|
||||
.font(.headline.monospacedDigit())
|
||||
.foregroundStyle(tint)
|
||||
}
|
||||
Chart(series) { point in
|
||||
AreaMark(x: .value("Time", point.time), y: .value("Value", point.value))
|
||||
.foregroundStyle(tint.opacity(0.12))
|
||||
LineMark(x: .value("Time", point.time), y: .value("Value", point.value))
|
||||
.foregroundStyle(tint)
|
||||
.lineStyle(StrokeStyle(lineWidth: 2.5))
|
||||
PointMark(x: .value("Time", point.time), y: .value("Value", point.value))
|
||||
.foregroundStyle(tint)
|
||||
}
|
||||
.chartYAxis { AxisMarks(position: .leading) }
|
||||
.frame(height: 135)
|
||||
.overlay {
|
||||
if series.isEmpty {
|
||||
Text("Waiting for live samples…")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(14)
|
||||
.background(tint.opacity(0.07), in: RoundedRectangle(cornerRadius: 12))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(Color(nsColor: .controlBackgroundColor), in: RoundedRectangle(cornerRadius: 12))
|
||||
.overlay(RoundedRectangle(cornerRadius: 12).stroke(tint.opacity(0.20)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4407,7 +4453,7 @@ private struct WorkbenchLiveMonitorScreen: View {
|
||||
if page == .serverStatus {
|
||||
Text("Server overview").font(.headline)
|
||||
ScrollView(.vertical) {
|
||||
WorkbenchServerOverview(rows: rows)
|
||||
WorkbenchServerOverview(rows: rows, samples: samples)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
|
||||
Reference in New Issue
Block a user