Recs rebuild WS1b-1: Recommendations tab (read-only surface)#1061
Merged
Conversation
Replace the Dashboard "Critical Issues" sub-tab with a "Recommendations" tab rendering the unified, de-duped RecommendationItem list (WS1a reader) as a card list grouped into collapsible Critical / Warning / Info sections. Each card shows a severity badge, the affected database, a headline + advice, a "Show T-SQL" expander with a working Copy button, and Apply + Mute buttons. Apply shows only when the row carries a built remediation action (engine rows); Mute shows only for engine-source rows. Apply + Mute are rendered DISABLED with an "Available in the next update" tooltip — the action wiring + informed-consent gate are deferred to WS1b-2. Header bar wires Refresh (re-runs the reader) and Generate now (runs an on-demand AnalysisService.AnalyzeAsync for the current server, then refreshes). States: loading spinner, all-clear empty state, and the engine-owned insufficient-data message (surfaced by Generate now). Grouping + state selection + Apply/Mute visibility live in a plain, WPF-free RecommendationsViewModel for unit testing (23 new tests). Lite untouched (later PR). CriticalIssuesContent left intact (unused). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…w query Investigate via the tools we already have, not a raw SELECT: - Incident findings (RecommendationItem.Setting == None: CPU/memory/blocking/ waits/plan-regression) get "Open in Active Queries -> " (deep-links to the Active Queries view scoped to the finding window +/- 1h grace, converting the finding's UTC window to server-local since collect.* timestamps are local) and "Ask AI" (copies an MCP investigation prompt for the user's robot friend). - Config-fix findings (Setting != None) get Copy fix / Apply; no deep-link (standing misconfig, not an incident). - Dropped the raw "Show T-SQL"/investigate_query affordance for investigation. ServerTab handles the deep-link (select Queries tab + QueryPerformanceContent .ShowActiveQueriesForRange, syncing the global range pickers). RecommendationItem carries WindowStartUtc/EndUtc; the reader populates them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s reader The legacy critical_issues "pressure/growth" families (Memory Pressure, Memory Grant Pressure, CPU Scheduling Pressure, Memory Clerk Growth) are noise — short-window deltas, no quantification, circular investigate queries — and are covered better by analysis-engine facts. Filter them out of the reader so a healthy server reads "all clear" instead of showing pressure-noise cards. The source rules are cut in install/50 in a follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Scope
The visible, read-only Recommendations tab (Dashboard-only) — WS1b of the recommendations-engine rebuild. Replaces the "Critical Issues" sub-tab with a "Recommendations" tab that renders the unified, de-duped
RecommendationItemlist (from the WS1aRecommendationsReader, already merged) as the approved layout: a card list grouped into collapsible Critical / Warning / Info sections.Each card shows: a severity badge (glyph + label, theme status brush), the affected database (bracketed), a headline (
Title), wrapped advice (AdviceText), a "Show T-SQL" expander revealingCopyPasteSqlin a monospace block with a working Copy button, and Apply + Mute buttons.Not in scope (deferred to WS1b-2): the Apply and Mute action wiring + the informed-consent gate. Apply + Mute render DISABLED with a tooltip "Available in the next update", so the full approved layout is reviewable with no half-working buttons. Not in scope: Lite (a later PR) — Lite is untouched here.
Visibility predicates (match the alert path)
Remediation != null(engine rows with a built, persisted action).Source == Engine(the legacy store has no mute concept).Header bar / actions (these ARE wired)
RecommendationsReader.GetRecommendationsAsyncfor the current server.AnalysisService.AnalyzeAsync(serverId, displayName, hoursBack: 4)for the current server (constructed exactly asAnalysisSchedulerdoes:SqlServerPlanFetcher+AnalysisService,serverIdviaServerIdHelper.GetDeterministicHashCode), then refreshes. I wired Generate-now live — the construction path is small and self-contained, so it did not pull in extra scope.States
LoadingOverlayspinner while reading.AnalysisService.InsufficientDataMessage(or a default "collecting data — recommendations appear after the engine has ≥24h of history"). Design note: this state is surfaced by Generate now (the engine owns the data-span determination viaMinimumDataHours); the read-only Refresh path shows Empty/Loaded. This avoids duplicating the span-check SQL or wideningAnalysisService's surface. A freshly-onboarded server therefore shows "All clear" on a plain Refresh and the "collecting data" message after Generate now.File:line changelog
New files
Dashboard/Controls/RecommendationsViewModel.cs— the pure, WPF-free core:RecommendationsViewModel.FromItems/Loading/InsufficientData(groups byCanonicalSeverityinto Critical→Warning→Info sections, empty sections omitted, Critical+Warning expanded / Info collapsed), theRecommendationsStateenum, andRecommendationCardViewModel/RecommendationSectionViewModelDTOs carrying the display flags +ShowApply/ShowMutepredicates.Dashboard/Controls/RecommendationsContent.xaml— the card-list-grouped-by-severity UI (Expanderper section,Expanderper card for "Show T-SQL"), header bar, and the four mutually-exclusive state regions. All themeDynamicResourcebrushes; no hardcoded colors (badge text uses a fixed dark glyph color over the colored badge, matching badge-on-status-color convention).Dashboard/Controls/RecommendationsContent.xaml.cs—Initialize(DatabaseService, ServerConnection, ICredentialService),SetTimeRange(hoursBack),RefreshDataAsync(),GenerateNowButton_Click(live),CopySql_Click(live), andApplyViewModelstate-swap.Dashboard.Tests/RecommendationsViewModelTests.cs— 23 VM unit tests (xUnit v3).Modified
Dashboard/ServerTab.xaml:283-286—<TabItem Header="Critical Issues"><controls:CriticalIssuesContent .../>→<TabItem Header="Recommendations"><controls:RecommendationsContent x:Name="RecommendationsTab"/>.Dashboard/ServerTab.xaml.cs:99—RecommendationsTab.Initialize(_databaseService, _serverConnection, _credentialService)(dropped the obsoleteInvestigateRequestedsubscribe/unsubscribe at old :100/:238);:124,:384—RecommendationsTab.SetTimeRange(...).Dashboard/ServerTab.Refresh.cs:195—RefreshOverviewTabAsyncnow awaitsRecommendationsTab.RefreshDataAsync()(same Overview-tab refresh slot the Critical Issues sub-tab used).Dashboard/ServerTab.TimeRange.cs:233,536,540— global-time-range + Overview paths now callRecommendationsTab.SetTimeRange(...)/RefreshDataAsync().CriticalIssuesContent.xaml(.cs)is left intact (unused) per the task. The now-unreferencedOnInvestigateCriticalIssue(inServerTab.DrillDown.cs) is harmless — no compiler warning, build clean.Test counts (real)
dotnet build PerformanceMonitor.sln -c Debug→ 0 errors (1 pre-existing warning inRemediationTests.cs, unrelated).dotnet test Dashboard.Tests --no-build→ 302 passed, 0 failed (279 baseline + 23 new).dotnet test Lite.Tests→ 360 passed, 0 failed (Lite untouched).RecommendationsViewModelTestsin isolation → 23 passed: grouping into severity sections (order, empty-section omission, intra-band order preserved, expand defaults, header count); state selection (loading / empty / loaded / insufficient-data with engine message + blank-fallback); Apply visibility (only whenRemediation != null, false for legacy); Mute visibility (only whenSource == Engine); card display flags (HasSql, DatabaseBracketed, SeverityLabel, disabled-tooltip).Deferred to WS1b-2
RemediationConfirmWindow) gate.Needs visual verification (launch the Dashboard)
WPF rendering is not unit-testable. Please launch the Dashboard and confirm: the Recommendations sub-tab (under Overview) renders the grouped collapsible sections; severity badges/colors; the "Show T-SQL" expander + Copy; Apply/Mute appear disabled with the tooltip and per the visibility rules; Refresh and Generate now behave; and the loading / empty / insufficient-data states display correctly.
🤖 Generated with Claude Code