Skip to content

Darling viewer wave 2: Queries, Blocking, Recommendations#1335

Merged
erikdarlingdata merged 2 commits into
devfrom
feature/1262-viewer-wave2
Jul 2, 2026
Merged

Darling viewer wave 2: Queries, Blocking, Recommendations#1335
erikdarlingdata merged 2 commits into
devfrom
feature/1262-viewer-wave2

Conversation

@erikdarlingdata

Copy link
Copy Markdown
Owner

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 is CAST(... AS bigint) because PG SUM(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 BlockedProcessAlertRow and the read calls the shared BlockedProcessReportMerge.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 extended StatusToBrushConverter (CRITICAL shares ERROR red, WARNING shares PERMISSIONS orange, INFO light blue). The detail pane composes the story via FactAdvice.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

  • ViewerDataService becomes partial with one file per surface; SQL stays public consts.
  • Wave-1 grid chrome hoisted into shared window resources (visual no-op) so four grids share one dark style.
  • Viewer gains project refs: Alerting (shared row/merge), Analysis (finding model + advice), Notifications (action serializer), Darling.Analysis (finding store).

Test plan

  • Darling.Tests full run: 145 passed, 12 skipped (all DARLING_TEST_PG-gated live tests), 0 failed — includes 33 new ungated tests in ViewerWave2Tests.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.
  • Viewer builds green; full solution builds green.
  • Lite and Dashboard build green (untouched).
  • Visual smoke against a live Darling store (validator).

Part of #1262.

🤖 Generated with Claude Code

erikdarlingdata and others added 2 commits July 2, 2026 15:34
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>
@erikdarlingdata erikdarlingdata merged commit b08b597 into dev Jul 2, 2026
2 checks passed
@erikdarlingdata erikdarlingdata deleted the feature/1262-viewer-wave2 branch July 2, 2026 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant