diff --git a/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs b/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs
index 9f092f0..854b987 100644
--- a/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs
+++ b/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs
@@ -1754,6 +1754,18 @@ private void ShowPropertiesPanel(PlanNode node)
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(16, 0, 0, 0)
});
+ if (!string.IsNullOrEmpty(w.ActionableFix))
+ {
+ warnPanel.Children.Add(new TextBlock
+ {
+ Text = w.ActionableFix,
+ FontSize = 11,
+ FontStyle = FontStyle.Italic,
+ Foreground = TooltipFgBrush,
+ TextWrapping = TextWrapping.Wrap,
+ Margin = new Thickness(16, 2, 0, 0)
+ });
+ }
planWarningsPanel.Children.Add(warnPanel);
}
diff --git a/src/PlanViewer.App/PlanViewer.App.csproj b/src/PlanViewer.App/PlanViewer.App.csproj
index c04c93b..c00ff0c 100644
--- a/src/PlanViewer.App/PlanViewer.App.csproj
+++ b/src/PlanViewer.App/PlanViewer.App.csproj
@@ -6,7 +6,7 @@
app.manifest
EDD.ico
true
- 1.7.0
+ 1.7.1
Erik Darling
Darling Data LLC
Performance Studio
diff --git a/src/PlanViewer.Core/Output/HtmlExporter.cs b/src/PlanViewer.Core/Output/HtmlExporter.cs
index e945151..897598c 100644
--- a/src/PlanViewer.Core/Output/HtmlExporter.cs
+++ b/src/PlanViewer.Core/Output/HtmlExporter.cs
@@ -187,6 +187,7 @@ .card h3 {
.warn-type { font-size: 0.75rem; font-weight: 600; }
.warn-benefit { font-size: 0.7rem; font-weight: 600; color: var(--text-muted); padding: 0.05rem 0.3rem; border-radius: 3px; background: rgba(0,0,0,0.04); }
.warn-msg { font-size: 0.8rem; color: var(--text); flex-basis: 100%; }
+.warn-fix { font-size: 0.75rem; color: var(--text-secondary); font-style: italic; flex-basis: 100%; border-left: 2px solid var(--border); padding-left: 0.5rem; margin-top: 0.15rem; }
/* Query text */
details { margin-bottom: 0.75rem; }
@@ -459,6 +460,8 @@ private static void WriteWarnings(StringBuilder sb, StatementResult stmt)
if (w.MaxBenefitPercent.HasValue)
sb.AppendLine($"up to {w.MaxBenefitPercent:N0}% benefit");
sb.AppendLine($"{Encode(w.Message)}");
+ if (!string.IsNullOrEmpty(w.ActionableFix))
+ sb.AppendLine($"{Encode(w.ActionableFix)}");
sb.AppendLine("");
}
sb.AppendLine("");
diff --git a/src/PlanViewer.Core/Output/TextFormatter.cs b/src/PlanViewer.Core/Output/TextFormatter.cs
index da655ad..d5ec7d1 100644
--- a/src/PlanViewer.Core/Output/TextFormatter.cs
+++ b/src/PlanViewer.Core/Output/TextFormatter.cs
@@ -172,6 +172,8 @@ public static void WriteText(AnalysisResult result, TextWriter writer)
? $" (up to {w.MaxBenefitPercent:N0}% benefit)"
: "";
writer.WriteLine($" [{w.Severity}] {w.Type}{benefitTag}: {EscapeNewlines(w.Message)}");
+ if (!string.IsNullOrEmpty(w.ActionableFix))
+ writer.WriteLine($" Fix: {EscapeNewlines(w.ActionableFix)}");
}
}
diff --git a/src/PlanViewer.Web/Pages/Index.razor b/src/PlanViewer.Web/Pages/Index.razor
index 3a54c88..0fc82d5 100644
--- a/src/PlanViewer.Web/Pages/Index.razor
+++ b/src/PlanViewer.Web/Pages/Index.razor
@@ -332,7 +332,10 @@ else
@if (infoCount > 0) { @infoCount }
- @foreach (var w in GetAllWarnings(ActiveStmt!))
+ @foreach (var w in GetAllWarnings(ActiveStmt!)
+ .OrderByDescending(x => x.MaxBenefitPercent ?? -1)
+ .ThenByDescending(x => x.Severity == "Critical" ? 3 : x.Severity == "Warning" ? 2 : 1)
+ .ThenBy(x => x.Type))
{
@w.Severity
@@ -341,7 +344,15 @@ else
@w.Operator
}
@w.Type
+ @if (w.MaxBenefitPercent.HasValue)
+ {
+ up to @w.MaxBenefitPercent.Value.ToString("N0")% benefit
+ }
@w.Message
+ @if (!string.IsNullOrEmpty(w.ActionableFix))
+ {
+ @w.ActionableFix
+ }
}
diff --git a/src/PlanViewer.Web/wwwroot/css/app.css b/src/PlanViewer.Web/wwwroot/css/app.css
index f512855..542cb5a 100644
--- a/src/PlanViewer.Web/wwwroot/css/app.css
+++ b/src/PlanViewer.Web/wwwroot/css/app.css
@@ -807,6 +807,26 @@ textarea::placeholder {
font-size: 0.75rem;
}
+.warn-benefit {
+ font-size: 0.7rem;
+ font-weight: 600;
+ color: var(--text-muted);
+ padding: 0.05rem 0.35rem;
+ border-radius: 3px;
+ background: rgba(0, 0, 0, 0.05);
+ margin-right: 0.4rem;
+}
+
+.warning-fix {
+ color: var(--text-secondary);
+ display: block;
+ margin-top: 0.25rem;
+ font-size: 0.75rem;
+ font-style: italic;
+ border-left: 2px solid var(--border);
+ padding-left: 0.5rem;
+}
+
/* === Query Text === */
.stmt-text-section {
margin-bottom: 0.75rem;