Darling viewer wave 2: Queries, Blocking, Recommendations#1335
Merged
Conversation
Restructures the viewer's right side into surface tabs (Overview unchanged) and adds three new ones, all lazy-loaded per tab (Lite's visible-only rule) with the 60-second refresh applying to the active tab only: - Queries: top-50 query-stats groups over 24h — database, truncated query text with tooltip, execution/CPU/duration/reads deltas, last execution (server time) — ranked by summed delta_elapsed_time like Lite's Top Queries default, latest text via LATERAL join, Lite's WAITFOR trim, every aggregate CAST back to bigint (PG SUM(bigint) returns numeric). - Blocking: XE blocked-process reports preferred with the always-on DMV snapshot merged in via the SHARED BlockedProcessReportMerge on the shared BlockedProcessAlertRow shape (the alert path's exact dedup/re-cap semantics), Source badge per row; the report-XML column is deliberately not fetched (nothing renders it this slice). - Recommendations: the latest analysis batch through the shared PgFindingStore contract, severity-banded with both apps' cutoffs (>=1.5 CRITICAL / >=0.75 WARNING) and colored by the extended status converter; detail pane composes the story via FactAdvice.GetForFinding plus the persisted remediation_action_json pretty-printed read-only — NO Apply in the viewer. Empty state documents the analysis cadence. The wave-1 grid chrome is hoisted into shared window resources (visual no-op) and ViewerDataService becomes partial with one file per surface. ViewerWave2Tests pins the SQL contracts ungated (windows, ORDER BY, LIMITs, the bigint casts, the shared-row merge through viewer rows) and unit-tests the pure helpers (severity banding, title/detail composition, JSON pretty-print, truncation, wait-time format, local-time conversion). Part of #1262 (headless plan, viewer wave 2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Viewer wave 2 for the Darling headless edition (#1262): the right side of the viewer becomes a TabControl — the wave-1 Overview (health grid + wait chart, unchanged) plus three new surfaces, each bound to the settled backend contracts. Loads are lazy per tab (Lite's visible-only rule): selecting a server or a tab loads only the active tab, and the 60-second refresh re-reads just that tab, with the wave-1 overlap guard extended to re-loop when the selection moves mid-flight.
Queries tab
Top-50 query-stats groups over the last 24 hours: Database, Query Text (one-line preview + tooltip), Executions, Total CPU (ms), Total Duration (ms), Total Reads, Last Execution (server time). Ranked by
SUM(delta_elapsed_time) DESC— Lite's verified default (its grid default-sorts TotalElapsedMs descending) — with Lite's over-fetch-then-WAITFOR-trim and the latest non-null text per group via a LATERAL join. Every aggregate isCAST(... AS bigint)because PGSUM(bigint)returns numeric.Blocking tab
Recent blocked processes, XE-preferred + DMV fallback with the SAME merged semantics as the alert path: the viewer row derives from the shared
BlockedProcessAlertRowand the read calls the sharedBlockedProcessReportMerge.AppendDmvFallbackRows(dedup by SPID pair within a minute, XE preferred, re-cap 200 newest). Columns: Event Time (local), Source badge (XE report vs DMV snapshot), Database, Blocked/Blocking SPID, Wait Time, Lock Mode, Contentious Object, Blocked/Blocking SQL previews with tooltips. The report-XML column is deliberately not fetched — nothing renders it this slice and it can run to hundreds of KB per row.Recommendations tab
The latest analysis run's findings read through the shared
PgFindingStore.GetLatestFindingsAsync(the V4 contract, incl.remediation_action_json). Severity bands use both apps' shared cutoffs (>= 1.5 CRITICAL, >= 0.75 WARNING, else INFO), colored by the extendedStatusToBrushConverter(CRITICAL shares ERROR red, WARNING shares PERMISSIONS orange, INFO light blue). The detail pane composes the story viaFactAdvice.GetForFinding(value-stated advice, any derivable copy-paste T-SQL) and pretty-prints the persisted remediation action as read-only JSON — NO Apply in the viewer this slice. Empty state: "no findings — analysis runs every 30 minutes once 24h of data exists."Plumbing
ViewerDataServicebecomes partial with one file per surface; SQL stays public consts.Test plan
Darling.Testsfull run: 145 passed, 12 skipped (allDARLING_TEST_PG-gated live tests), 0 failed — includes 33 new ungated tests inViewerWave2Tests.cs: SQL-const pins for all three reads (windows, ORDER BY, LIMITs, the bigint casts, the no-XML trim), the shared merge exercised through the viewer row type, severity banding/sort/title/detail composition, remediation JSON pretty-print round-trip, truncation/wait-time/local-time helpers, and the converter's new bands.Part of #1262.
🤖 Generated with Claude Code