From 35496d5a0df23b7e3f90c6762f13682e9cd57cca Mon Sep 17 00:00:00 2001 From: Hannah Vernon Date: Tue, 10 Mar 2026 17:08:56 -0500 Subject: [PATCH 1/5] Pre-fill context fields and add default expiration setting - Parse detail_text to extract Database, Query Text, and Wait Type when using 'Mute This Alert' from alert history (both editions) - Add PopulateFromDetailText() to AlertMuteContext for structured field extraction from the label: value format - Add 'Default expiration for new mute rules' dropdown to Settings in both editions (1 hour, 24 hours, 7 days, Never; default 24h) - MuteRuleDialog now selects the configured default expiration instead of always defaulting to 'Never' - Persist setting as mute_rule_default_expiration in settings.json (Lite) and preferences.json (Dashboard) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Controls/AlertsHistoryContent.xaml.cs | 1 + Dashboard/MainWindow.xaml.cs | 1 + Dashboard/Models/MuteRule.cs | 21 +++++++++++++++++++ Dashboard/Models/UserPreferences.cs | 3 +++ Dashboard/MuteRuleDialog.xaml.cs | 18 ++++++++++++++++ Dashboard/SettingsWindow.xaml | 9 ++++++++ Dashboard/SettingsWindow.xaml.cs | 11 ++++++++++ Lite/App.xaml.cs | 7 +++++++ Lite/Controls/AlertsHistoryTab.xaml.cs | 1 + Lite/Models/MuteRule.cs | 21 +++++++++++++++++++ Lite/Windows/MuteRuleDialog.xaml.cs | 12 +++++++++++ Lite/Windows/SettingsWindow.xaml | 12 ++++++++++- Lite/Windows/SettingsWindow.xaml.cs | 10 +++++++++ 13 files changed, 126 insertions(+), 1 deletion(-) diff --git a/Dashboard/Controls/AlertsHistoryContent.xaml.cs b/Dashboard/Controls/AlertsHistoryContent.xaml.cs index 9c4469be..03e28753 100644 --- a/Dashboard/Controls/AlertsHistoryContent.xaml.cs +++ b/Dashboard/Controls/AlertsHistoryContent.xaml.cs @@ -482,6 +482,7 @@ private void MuteThisAlert_Click(object sender, RoutedEventArgs e) ServerName = item.ServerName, MetricName = item.MetricName }; + context.PopulateFromDetailText(item.DetailText); var dialog = new MuteRuleDialog(context) { Owner = Window.GetWindow(this) }; if (dialog.ShowDialog() == true) diff --git a/Dashboard/MainWindow.xaml.cs b/Dashboard/MainWindow.xaml.cs index 99008b11..a6f4eec8 100644 --- a/Dashboard/MainWindow.xaml.cs +++ b/Dashboard/MainWindow.xaml.cs @@ -151,6 +151,7 @@ private async void MainWindow_Loaded(object sender, RoutedEventArgs e) // Sync preferences var startupPrefs = _preferencesService.GetPreferences(); TabHelpers.CsvSeparator = startupPrefs.CsvSeparator; + MuteRuleDialog.DefaultExpiration = startupPrefs.MuteRuleDefaultExpiration; if (Enum.TryParse(startupPrefs.TimeDisplayMode, out var tdm)) Helpers.ServerTimeHelper.CurrentDisplayMode = tdm; diff --git a/Dashboard/Models/MuteRule.cs b/Dashboard/Models/MuteRule.cs index ba0e97e4..0b6e3e7b 100644 --- a/Dashboard/Models/MuteRule.cs +++ b/Dashboard/Models/MuteRule.cs @@ -82,5 +82,26 @@ public class AlertMuteContext public string? QueryText { get; set; } public string? WaitType { get; set; } public string? JobName { get; set; } + + /// + /// Extracts context fields (Database, Query, Wait Type, Job Name) from the + /// structured detail_text stored with each alert. The format is label/value + /// pairs indented with two spaces, e.g. " Database: MyDB". + /// + public void PopulateFromDetailText(string? detailText) + { + if (string.IsNullOrEmpty(detailText)) return; + + foreach (var line in detailText.Split('\n')) + { + var trimmed = line.TrimStart(); + if (DatabaseName == null && trimmed.StartsWith("Database: ", StringComparison.Ordinal)) + DatabaseName = trimmed.Substring("Database: ".Length).Trim(); + else if (QueryText == null && trimmed.StartsWith("Query: ", StringComparison.Ordinal)) + QueryText = trimmed.Substring("Query: ".Length).Trim(); + else if (WaitType == null && trimmed.StartsWith("Wait Type: ", StringComparison.Ordinal)) + WaitType = trimmed.Substring("Wait Type: ".Length).Trim(); + } + } } } diff --git a/Dashboard/Models/UserPreferences.cs b/Dashboard/Models/UserPreferences.cs index aa2a3cd3..9276408c 100644 --- a/Dashboard/Models/UserPreferences.cs +++ b/Dashboard/Models/UserPreferences.cs @@ -141,6 +141,9 @@ private static string GetDefaultCsvSeparator() // Alert database exclusions public List AlertExcludedDatabases { get; set; } = new(); + // Default mute rule expiration ("1 hour", "24 hours", "7 days", "Never") + public string MuteRuleDefaultExpiration { get; set; } = "24 hours"; + // Alert suppression (persisted) public List SilencedServers { get; set; } = new(); public List SilencedServerTabs { get; set; } = new(); diff --git a/Dashboard/MuteRuleDialog.xaml.cs b/Dashboard/MuteRuleDialog.xaml.cs index 104441d8..a24a0559 100644 --- a/Dashboard/MuteRuleDialog.xaml.cs +++ b/Dashboard/MuteRuleDialog.xaml.cs @@ -17,6 +17,12 @@ public partial class MuteRuleDialog : Window { public MuteRule Rule { get; private set; } + /// + /// Default expiration selection for new mute rules. + /// Set from UserPreferences at startup. Values: "1 hour", "24 hours", "7 days", "Never". + /// + public static string DefaultExpiration { get; set; } = "24 hours"; + public MuteRuleDialog(MuteRule? existingRule = null) { InitializeComponent(); @@ -31,6 +37,7 @@ public MuteRuleDialog(MuteRule? existingRule = null) else { Rule = new MuteRule(); + ApplyDefaultExpiration(); } } @@ -148,5 +155,16 @@ private void MetricCombo_SelectionChanged(object sender, SelectionChangedEventAr PatternFieldsGrid.Visibility = (showDatabase || showWaitType || showQueryText || showJobName) ? Visibility.Visible : Visibility.Collapsed; } + + private void ApplyDefaultExpiration() + { + ExpirationCombo.SelectedIndex = DefaultExpiration switch + { + "1 hour" => 0, + "24 hours" => 1, + "7 days" => 2, + _ => 3 + }; + } } } diff --git a/Dashboard/SettingsWindow.xaml b/Dashboard/SettingsWindow.xaml index 2b73cba6..e626d4ec 100644 --- a/Dashboard/SettingsWindow.xaml +++ b/Dashboard/SettingsWindow.xaml @@ -286,6 +286,15 @@ + + + + + + + + +