Skip to content

Commit 9447cb1

Browse files
Merge pull request #751 from erikdarlingdata/fix/display-mode-pickers
Make custom range pickers respect display mode
2 parents acbd0f6 + 506e691 commit 9447cb1

4 files changed

Lines changed: 119 additions & 38 deletions

File tree

Dashboard/Helpers/ServerTimeHelper.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ public static DateTime ToLocalTime(DateTime serverTime)
7070
_ => serverTime
7171
};
7272

73+
/// <summary>
74+
/// Converts a display-mode DateTime back to server time. Reverse of ConvertForDisplay.
75+
/// </summary>
76+
public static DateTime DisplayTimeToServerTime(DateTime displayTime, TimeDisplayMode mode) => mode switch
77+
{
78+
TimeDisplayMode.LocalTime => ToServerTime(displayTime),
79+
TimeDisplayMode.UTC => displayTime.AddMinutes(_utcOffsetMinutes),
80+
_ => displayTime
81+
};
82+
7383
/// <summary>
7484
/// Returns a short timezone label for the current display mode (e.g., "UTC", "PST", "UTC-8:00").
7585
/// </summary>

Dashboard/ServerTab.xaml.cs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public partial class ServerTab : UserControl
4747
private readonly UserPreferencesService _preferencesService;
4848
private DispatcherTimer? _autoRefreshTimer;
4949
private bool _isRefreshing;
50+
private bool _suppressPickerUpdates;
5051

5152
// Filter state dictionaries for each DataGrid
5253

@@ -663,11 +664,13 @@ private async void GlobalTimeRange_Click(object sender, RoutedEventArgs e)
663664

664665
private async void GlobalCustomDateTime_Changed(object sender, SelectionChangedEventArgs e)
665666
{
667+
if (_suppressPickerUpdates) return;
666668
await UpdateGlobalDateTimeRange();
667669
}
668670

669671
private async void GlobalTimeCombo_Changed(object sender, SelectionChangedEventArgs e)
670672
{
673+
if (_suppressPickerUpdates) return;
671674
// Only update if both dates are selected (time change alone isn't meaningful without dates)
672675
if (GlobalFromDate.SelectedDate.HasValue && GlobalToDate.SelectedDate.HasValue)
673676
{
@@ -684,10 +687,10 @@ private async Task UpdateGlobalDateTimeRange()
684687

685688
if (fromDateTime.HasValue && toDateTime.HasValue)
686689
{
687-
/* Convert local dates/times to server time - user picks in their timezone,
688-
but database stores collection_time in server's timezone */
689-
_globalFromDate = Helpers.ServerTimeHelper.ToServerTime(fromDateTime.Value);
690-
_globalToDate = Helpers.ServerTimeHelper.ToServerTime(toDateTime.Value);
690+
/* Convert display-mode time back to server time — pickers show time
691+
in the current display mode (server, local, or UTC) */
692+
_globalFromDate = Helpers.ServerTimeHelper.DisplayTimeToServerTime(fromDateTime.Value, Helpers.ServerTimeHelper.CurrentDisplayMode);
693+
_globalToDate = Helpers.ServerTimeHelper.DisplayTimeToServerTime(toDateTime.Value, Helpers.ServerTimeHelper.CurrentDisplayMode);
691694

692695
if (_globalFromDate > _globalToDate)
693696
{
@@ -1686,7 +1689,27 @@ private void TimeDisplayMode_SelectionChanged(object sender, SelectionChangedEve
16861689
};
16871690
if (mode == ServerTimeHelper.CurrentDisplayMode) return;
16881691

1689-
ServerTimeHelper.CurrentDisplayMode = mode;
1692+
// Re-convert custom range pickers from old display mode to new.
1693+
// Suppress picker change handlers to avoid validation errors and cascading refreshes.
1694+
var oldMode = ServerTimeHelper.CurrentDisplayMode;
1695+
var fromPicker = GetDateTimeFromPickers(GlobalFromDate, GlobalFromHour, GlobalFromMinute);
1696+
var toPicker = GetDateTimeFromPickers(GlobalToDate, GlobalToHour, GlobalToMinute);
1697+
_suppressPickerUpdates = true;
1698+
try
1699+
{
1700+
ServerTimeHelper.CurrentDisplayMode = mode;
1701+
if (fromPicker.HasValue && toPicker.HasValue)
1702+
{
1703+
var fromServer = Helpers.ServerTimeHelper.DisplayTimeToServerTime(fromPicker.Value, oldMode);
1704+
var toServer = Helpers.ServerTimeHelper.DisplayTimeToServerTime(toPicker.Value, oldMode);
1705+
SetPickersFromDateTime(fromServer, GlobalFromDate, GlobalFromHour, GlobalFromMinute);
1706+
SetPickersFromDateTime(toServer, GlobalToDate, GlobalToHour, GlobalToMinute);
1707+
}
1708+
}
1709+
finally
1710+
{
1711+
_suppressPickerUpdates = false;
1712+
}
16901713

16911714
// Persist preference
16921715
var prefs = _preferencesService.GetPreferences();

Lite/Controls/ServerTab.xaml.cs

Lines changed: 71 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -429,11 +429,11 @@ private void InitializeTimeComboBoxes()
429429

430430
private void SetPickersFromDateTime(DateTime serverTime, DatePicker datePicker, ComboBox hourCombo, ComboBox minuteCombo)
431431
{
432-
/* Convert server time to local time for display in UI */
433-
var localTime = ServerTimeHelper.ToLocalTime(serverTime);
434-
datePicker.SelectedDate = localTime.Date;
435-
hourCombo.SelectedIndex = localTime.Hour;
436-
minuteCombo.SelectedIndex = localTime.Minute / 15;
432+
/* Convert server time to the current display mode for UI */
433+
var displayTime = ServerTimeHelper.ConvertForDisplay(serverTime, ServerTimeHelper.CurrentDisplayMode);
434+
datePicker.SelectedDate = displayTime.Date;
435+
hourCombo.SelectedIndex = displayTime.Hour;
436+
minuteCombo.SelectedIndex = displayTime.Minute / 15;
437437
}
438438

439439
/// <summary>
@@ -549,7 +549,44 @@ private void TimeDisplayMode_SelectionChanged(object sender, SelectionChangedEve
549549
};
550550
if (mode == ServerTimeHelper.CurrentDisplayMode) return;
551551

552-
ServerTimeHelper.CurrentDisplayMode = mode;
552+
// Re-convert custom range pickers from old display mode to new.
553+
// Suppress refreshes while updating pickers to avoid cascading queries.
554+
var oldMode = ServerTimeHelper.CurrentDisplayMode;
555+
_isRefreshing = true;
556+
try
557+
{
558+
if (IsCustomRange)
559+
{
560+
var fromPicker = GetDateTimeFromPickers(FromDatePicker!, FromHourCombo, FromMinuteCombo);
561+
var toPicker = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
562+
if (fromPicker.HasValue && toPicker.HasValue)
563+
{
564+
var fromServer = ServerTimeHelper.DisplayTimeToServerTime(fromPicker.Value, oldMode);
565+
var toServer = ServerTimeHelper.DisplayTimeToServerTime(toPicker.Value, oldMode);
566+
ServerTimeHelper.CurrentDisplayMode = mode;
567+
var fromNew = ServerTimeHelper.ConvertForDisplay(fromServer, mode);
568+
var toNew = ServerTimeHelper.ConvertForDisplay(toServer, mode);
569+
FromDatePicker.SelectedDate = fromNew.Date;
570+
FromHourCombo.SelectedIndex = fromNew.Hour;
571+
FromMinuteCombo.SelectedIndex = fromNew.Minute / 15;
572+
ToDatePicker.SelectedDate = toNew.Date;
573+
ToHourCombo.SelectedIndex = toNew.Hour;
574+
ToMinuteCombo.SelectedIndex = toNew.Minute / 15;
575+
}
576+
else
577+
{
578+
ServerTimeHelper.CurrentDisplayMode = mode;
579+
}
580+
}
581+
else
582+
{
583+
ServerTimeHelper.CurrentDisplayMode = mode;
584+
}
585+
}
586+
finally
587+
{
588+
_isRefreshing = false;
589+
}
553590

554591
// Refresh all DataGrid bindings so ServerTimeConverter re-evaluates
555592
QuerySnapshotsGrid.Items.Refresh();
@@ -742,8 +779,8 @@ private async System.Threading.Tasks.Task RefreshAllDataAsync(bool fullRefresh =
742779
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
743780
if (fromLocal.HasValue && toLocal.HasValue)
744781
{
745-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
746-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
782+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
783+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
747784
}
748785
}
749786

@@ -1435,8 +1472,8 @@ private async System.Threading.Tasks.Task LoadBlockingSlicerAsync()
14351472
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
14361473
if (fromLocal.HasValue && toLocal.HasValue)
14371474
{
1438-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
1439-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
1475+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
1476+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
14401477
}
14411478
}
14421479

@@ -1522,8 +1559,8 @@ private async System.Threading.Tasks.Task LoadDeadlockSlicerAsync()
15221559
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
15231560
if (fromLocal.HasValue && toLocal.HasValue)
15241561
{
1525-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
1526-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
1562+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
1563+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
15271564
}
15281565
}
15291566

@@ -1667,8 +1704,8 @@ private async void MainTabControl_SelectionChanged(object sender, SelectionChang
16671704
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
16681705
if (fromLocal.HasValue && toLocal.HasValue)
16691706
{
1670-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
1671-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
1707+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
1708+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
16721709
}
16731710
}
16741711
await RefreshVisibleTabAsync(hoursBack, fromDate, toDate, subTabOnly: true);
@@ -2578,8 +2615,8 @@ private void UpdateQueryStoreDurationTrendChart(List<QueryTrendPoint> data)
25782615
var fromLocal = GetDateTimeFromPickers(FromDatePicker!, FromHourCombo, FromMinuteCombo);
25792616
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
25802617
if (fromLocal.HasValue && toLocal.HasValue)
2581-
return (ServerTimeHelper.LocalToServerTime(fromLocal.Value),
2582-
ServerTimeHelper.LocalToServerTime(toLocal.Value));
2618+
return (ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode),
2619+
ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode));
25832620
}
25842621
return (null, null);
25852622
}
@@ -2908,8 +2945,8 @@ private async void HeatmapMetric_SelectionChanged(object sender, SelectionChange
29082945
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
29092946
if (fromLocal.HasValue && toLocal.HasValue)
29102947
{
2911-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
2912-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
2948+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
2949+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
29132950
}
29142951
}
29152952
var metric = (HeatmapMetric)HeatmapMetricCombo.SelectedIndex;
@@ -3205,7 +3242,8 @@ private async void OnHeatmapDrillDown(DateTime bucketTimeUtc)
32053242
/// </summary>
32063243
private void SetDrillDownTimeRange(DateTime fromServer, DateTime toServer)
32073244
{
3208-
// Display in the current time mode (server time, local time, or UTC)
3245+
// Pickers store time in the current display mode. Downstream reads use
3246+
// DisplayTimeToServerTime() to convert back.
32093247
var fromDisplay = ServerTimeHelper.ConvertForDisplay(fromServer, ServerTimeHelper.CurrentDisplayMode);
32103248
var toDisplay = ServerTimeHelper.ConvertForDisplay(toServer, ServerTimeHelper.CurrentDisplayMode);
32113249

@@ -3261,8 +3299,8 @@ private async System.Threading.Tasks.Task UpdateWaitStatsChartFromPickerAsync()
32613299
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
32623300
if (fromLocal.HasValue && toLocal.HasValue)
32633301
{
3264-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
3265-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
3302+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
3303+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
32663304
}
32673305
}
32683306
double globalMax = 0;
@@ -3411,8 +3449,8 @@ private async System.Threading.Tasks.Task UpdateMemoryClerksChartFromPickerAsync
34113449
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
34123450
if (fromLocal.HasValue && toLocal.HasValue)
34133451
{
3414-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
3415-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
3452+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
3453+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
34163454
}
34173455
}
34183456

@@ -3621,8 +3659,8 @@ private async System.Threading.Tasks.Task UpdatePerfmonChartFromPickerAsync()
36213659
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
36223660
if (fromLocal.HasValue && toLocal.HasValue)
36233661
{
3624-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
3625-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
3662+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
3663+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
36263664
}
36273665
}
36283666
double globalMax = 0;
@@ -4615,8 +4653,8 @@ private async System.Threading.Tasks.Task LoadActiveQueriesSlicerAsync()
46154653
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
46164654
if (fromLocal.HasValue && toLocal.HasValue)
46174655
{
4618-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
4619-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
4656+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
4657+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
46204658
}
46214659
}
46224660

@@ -4720,8 +4758,8 @@ private async System.Threading.Tasks.Task LoadQueryStatsSlicerAsync()
47204758
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
47214759
if (fromLocal.HasValue && toLocal.HasValue)
47224760
{
4723-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
4724-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
4761+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
4762+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
47254763
}
47264764
}
47274765

@@ -4818,8 +4856,8 @@ private async System.Threading.Tasks.Task LoadQueryStoreSlicerAsync()
48184856
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
48194857
if (fromLocal.HasValue && toLocal.HasValue)
48204858
{
4821-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
4822-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
4859+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
4860+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
48234861
}
48244862
}
48254863

@@ -4914,8 +4952,8 @@ private async System.Threading.Tasks.Task LoadProcStatsSlicerAsync()
49144952
var toLocal = GetDateTimeFromPickers(ToDatePicker!, ToHourCombo, ToMinuteCombo);
49154953
if (fromLocal.HasValue && toLocal.HasValue)
49164954
{
4917-
fromDate = ServerTimeHelper.LocalToServerTime(fromLocal.Value);
4918-
toDate = ServerTimeHelper.LocalToServerTime(toLocal.Value);
4955+
fromDate = ServerTimeHelper.DisplayTimeToServerTime(fromLocal.Value, ServerTimeHelper.CurrentDisplayMode);
4956+
toDate = ServerTimeHelper.DisplayTimeToServerTime(toLocal.Value, ServerTimeHelper.CurrentDisplayMode);
49194957
}
49204958
}
49214959

Lite/Services/LocalDataService.Blocking.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ public static DateTime ToLocalTime(DateTime serverTime)
6767
_ => serverTime
6868
};
6969

70+
/// <summary>
71+
/// Converts a display-mode DateTime back to server time. Reverse of ConvertForDisplay.
72+
/// </summary>
73+
public static DateTime DisplayTimeToServerTime(DateTime displayTime, Helpers.TimeDisplayMode mode) => mode switch
74+
{
75+
Helpers.TimeDisplayMode.LocalTime => LocalToServerTime(displayTime),
76+
Helpers.TimeDisplayMode.UTC => displayTime.AddMinutes(_utcOffsetMinutes),
77+
_ => displayTime
78+
};
79+
7080
/// <summary>
7181
/// Returns a short timezone label for the current display mode.
7282
/// </summary>

0 commit comments

Comments
 (0)