Skip to content

Lite: Collection Log, System Events, Config Changes and Long Queries say where the data starts, and Duration Trends draws the whole range (#4966, group C) - #4989

Merged
erikdarlingdata merged 13 commits into
devfrom
feature/4966-lite-c
Oct 3, 2026
Merged

erikdarlingdata merged 13 commits into
devfrom
feature/4966-lite-c

Conversation

@erikdarlingdata

@erikdarlingdata erikdarlingdata commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Part of #4966.

Why

When a time range starts before a server's data coverage, the Lite grids drew the shorter range with no notice, so a reader could take the missing span for a quiet period. The Queries tab, Active Queries and Current Waits already say "Showing since " through one shared probe. This PR covers the Collection Health, System Events, Config Changes and Long Queries surfaces (18 surfaces) of Lite's list in the issue.

What changes

Seven new QueryWindowRelation members, each with its view and, for the event and snapshot tables, the collector whose runs in v_collection_log show the store covered a quiet start:

Relation View Coverage from
CollectionLog v_collection_log rows only (the log is the run record)
SystemHealthEvents v_system_health_events system_health_events runs
DefaultTraceEvents v_default_trace_events default_trace_events runs
ServerConfig v_server_config server_config runs
DatabaseConfig v_database_config database_config runs
TraceFlags v_trace_flags trace_flags runs
LongQueryCompletions v_long_query_completions long_query_completions runs

The probe measures each relation on the column that surface's grid filters on, so a banner never names a time later than the earliest row its grid shows. That is one more closed map, QueryWindowRelationTimeColumn: capture_time for the three config snapshots (their collectors stamp it, and the archive purges by it), event_time for the System Events and Default Trace relations (see the surface list), and collection_time for every other relation, so the existing relations return what they returned before.

Each surface that gets a notice has a banner TextBlock beside its grid and one call, RefreshStoredWindowBannerAsync(relation, banner, hoursBack, fromDate, toDate), made after the rows are bound from the one method that surface's read runs through. The sub-tab switch, a range change and the surface's own Refresh button all reach that method, and a probe that throws hides the banner and lets the refresh go on (the shared ProbeWindowFloorOrNullAsync). The helper takes the same UTC window the read took (GetQueriesTabWindowUtc).

Every surface and its result

Collection Health (3)

  • Health Summary: no notice. It reads a fixed last-7-days aggregate per collector (GetCollectionHealthAsync(int serverId) takes no range), so a picked range never starts before its data.
  • Collection Log: notice (CollectionLog).
  • Duration Trends: no notice. The chart reads its own buckets over the whole asked range (not the Collection Log grid's capped page) and pins its X axis to that range, so what it draws is the range's data and the empty span is the span with none.

System Events (11)

  • Corruption Events: no notice. The charts pin their X axis to the asked range (SystemHealthChartRenderer calls SetLimitsX(xMin, xMax) in each render).
  • Contention Events: no notice, same reason.
  • Scheduler Issues, Severe Errors, Memory Conditions, Memory Broker, Memory Node OOM, Significant Waits, CPU Tasks and I/O Issues: notice each (SystemHealthEvents, one banner per sub-tab). The probe measures on event_time, the event's own time and the column all eight grids filter on, not on collection_time. A server's first run can store events from before itself, every row stamped with that run's collection_time while its event_time is older (about 10 minutes for system_health, whose first run reads back its first-run window; days for the Default Trace, whose first run stores the history the trace files hold), so measuring the run's time put "Showing since " above rows from before it. Now the banner names the oldest stored event when the range starts before it, and no banner shows when the history reaches back to the range start. The collector-run part of the probe stays on collection_time.
  • Default Trace: notice (DefaultTraceEvents). It measures on event_time, the column its grid filters on, for the same reason. That column holds the monitored server's wall-clock time as stored, and the grid converts each row to UTC through the server's clock, so the probe does the same. A new QueryWindowRelationTimeIsServerLocal method marks this relation, and GetQueryWindowFloorAsync takes an optional ServerClock (falling back to the active server clock, as the grid does). For this relation it reads the candidate rows over the grid's window widened by an hour on each side, converts each row with the offset in force at its own date, and uses the converted times for the oldest-row and older-row checks, so the banner's time and the before-or-after-the-range test are exact on a server whose clock is not UTC and across a daylight-saving change. The collector's runs are UTC, so the first run and the first row are compared in C#, not in one LEAST. Every UTC relation keeps the single query, and the system_health event_time (the XE timestamp, UTC) is not shifted.

Config Changes (3)

  • Server Config Changes, Database Config Changes and Trace Flag Changes: notice each (ServerConfig, DatabaseConfig, TraceFlags). The collectors run at load, so the table is sparse by design and the collector's runs are what show a quiet start was covered.

Long Queries (1)

  • Notice (LongQueryCompletions). The banner sits above the existing "trace is off" warning in a small StackPanel, so both can show at once. The grid lists only the newest 200 completions (LocalDataService.LongQueryGridCap, now the one value behind the read's LIMIT), so a read that fills that cap words the notice at the oldest completion it returned (its event time, in UTC), even where the store covers the range and with no 90-minute slack, while a read under the cap keeps the coverage notice, or names the oldest completion it shows (at its event time) when that is earlier: a server's first run stores completions from up to 10 minutes before itself, and the grid shows each at its event time, so the notice no longer names a time later than a completion on the screen. The Collection Log grid, which lists its newest 500 runs (CollectionLogGridCap), words its capped read the same way.

Totals: 14 banners added over 7 relations, 4 surfaces with no notice, 0 surfaces left over.

Duration Trends chart, Long Queries notice and first-run wording

  • Duration Trends draws the whole range. The Collection Health refresh used to hand the Collection Log grid's page (the newest 500 runs) to the chart, whose X axis is pinned to the full range. At about 20 runs a minute, "Last 24 hours" drew the newest 25 minutes and left about 23.5 hours of axis empty though the store held those runs. The chart now has its own read, GetCollectorDurationTrendAsync, started beside the grid's read: per collector and time bucket over the asked range, from v_collection_log, over the successful runs the chart always drew, with the maximum and average duration and the run count, and each bucket's start clamped to the window start (GREATEST, as the bucketed duration-trend reads do). The bucket width is the one the other desktop trend charts use for the range, TrendBuckets.AutoMinutes(rangeMinutes, 1, TrendBudget.Chart.AutoPoints): 1 minute for 24 hours, 10 minutes for 7 days. That budget is one series' share, and this chart draws one line per collector. The chart draws each collector's bucket maximum, so a slow run still shows as it did when every run was a point, and the hover adds a fourth line, "Slowest of N runs; average X ms". The grid keeps its 500-row page and its cap note. The hover popup takes an optional per-point detail line, keyed by the point's X (ChartHoverHelper.Add(scatter, label, pointDetails) with an IReadOnlyDictionary<double, string>, shared with the Darling viewer, which passes none); without it the popup is the three lines it was.
  • Long Queries under its cap names the oldest completion shown. The grid shows each completion at its event time, and a first run stores completions up to 10 minutes older than itself, while the probe measures the run's time. Under the cap the notice now names the earlier of the coverage start and the oldest completion shown (LongQueryRowTimeUtc), the rule the Darling viewer's event grids follow. It is one step shared by the capped grids (EarlierOfFloorAndRowShown); for the Collection Log and Plan Corrections the grid's rows are on the probe's own column, so their words do not change. The capped path is unchanged.
  • First-run history depth, stated correctly. The probe's doc comment and this description said a first run stores event history going back days. That holds for the Default Trace only: system_health and Long Queries reach about 10 minutes back (CollectorContext.EventFallbackWindow). Both are corrected, and so are the matching test comments.
  • The hover's detail line is found by the point's X, not its position. The line breaks at every collection gap by inserting a point of its own (a NaN between the two buckets), so a line taken by position fell one bucket behind after each break: every bucket after the first break showed the next bucket's "Slowest of N runs; average X ms", and the last showed none. With 20 buckets and one break, bucket 10 said "Slowest of 12 runs; average 61 ms" instead of its own "Slowest of 11 runs; average 60 ms". The shared hover now looks the line up by the X of the point it picked, and Lite builds the keys from the same X values the scatter is drawn from (CollectorDurationSeries.DetailsByX), so the lookup is exact and the point a break inserts has no line. A bar that beats the series' nearest point still carries no detail line, and a series without details keeps the three-line text. What the hover shows for a mouse position is now one internal method, ChartHoverHelper.HoverTextAt(pixel), which the mouse handler calls, so it can be asked without a mouse.
  • The Y axis says what is drawn. The chart draws each bucket's slowest run, but its axis read "Duration (ms)". It now reads "Slowest run per bucket (ms)", the same words as the Darling viewer's chart.
  • An empty range clears the hover. The empty-range path returned before the hover was cleared, so a tooltip registered by the previous range could stay on an empty chart. The hover is now cleared right after the chart is, before that return.

Notes

  • The Health Summary's drill-down window (the per-collector Collection Log window) reads a fixed 168 hours, not the picker's range, so it needs no notice either.
  • The System Events and Default Trace relations are measured on event_time, as the surface list says, and the archive still purges those two tables by collection_time. Long Queries stays on collection_time because its grid filters on that column.
  • The existing test EveryRelation_NamesARealArchiveView_WithServerIdAndCollectionTime is renamed ..._WithServerIdAndItsTimeColumn and now reads each relation's column from the new map. Reason: the config snapshots' column is capture_time and the two event relations' is event_time. It still requires every view to be archivable with server_id and that column, and pins the archive's own time column to the same value, except for the two event relations, where it pins collection_time as the archive's column and requires the view to carry both columns.

Test plan

  • New DataStartBannerSurfaceTests (37 tests). Before the banners and calls were added: 15 failed (the 14 per-surface wiring cases and the helper pin) and 22 passed. After: 37 passed.
  • Per relation, rows starting inside a 7-day range read the notice back, worded at the first row or run (7 tests), and a quiet start shows none (7 tests). The quiet start for an event or snapshot table has a month of logged runs and a first row three days into the range; for the Collection Log the oldest row is a month old.
  • Mapping test pins each relation's view, collector and time column (7 cases). Source pins check each of the 14 banners exists in ServerTab.xaml and its call follows the grid's bind, and that the four no-notice surfaces keep the shape that needs none.
  • DataStartBannerTests, DataStartBannerProbeFailureTests, QueryWindowTruncationTests, ComparisonWindowUtcTests, DisplayZoneTextFrameTests, RepoFileAdoptionTests and every class that names a file this PR touches (27 classes): 410 passed, 0 failed. After merging origin/dev, rebuilt with 0 warnings and re-ran the keep-green classes: 119 passed, 0 failed.
  • Event-time probe, for each of the two event relations (T0 the first run, H the oldest stored event_time, S the range start): history reaching to H with S < H < T0 names H, not T0 (before the fix both relations read T0: "Showing since" the run's time); history reaching back to the range start (H <= S) shows no banner; no stored history names T0. The seeder sets event_time and collection_time apart for these tables. DataStartBannerSurfaceTests (43), DataStartBannerTests, DataStartBannerProbeFailureTests, QueryWindowTruncationTests, ComparisonWindowUtcTests, DisplayZoneTextFrameTests and seven neighbouring source-scanning classes: 135 passed, 0 failed, 0 warnings. StoredEventCopiesSweepTests failed on this branch before the fix because the probe's two view-name reads (system_health events and long query completions) were not on its list; it now lists them with the reason.
  • Default Trace on a server that is not on UTC, rows stored as the server's local time (T0 the first run, H the oldest stored event, S the range start): on a clock 5 hours behind UTC, S < H < T0 names H in UTC, not H less 5 hours and not T0; H 3 hours after S in UTC but 2 hours before S as stored shows the banner (before the fix it was hidden); on a clock 5 hours ahead of UTC, H before S in UTC but after S as stored shows no banner, with H half an hour and 72 hours before S (a clock behind UTC cannot produce that layout, because its stored time reads earlier than the instant, so the ahead case stands in for it); four US Eastern rows across the 8 March and 1 November changes, the oldest on each side of each change, give the exact UTC time and equal the oldest row the grid shows; a probe given no clock uses the active one; system_health is not shifted by a clock. Before the fix 8 of these 12 new tests failed (the first: the banner said 2026-09-28 23:22 where 2026-09-29 04: was expected, the 5-hour shift). After: DataStartBannerSurfaceTests 55 passed; the 43 classes that name the clock, the probe or the grid's read 585 passed; 10 more source-scanning classes 81 passed; 0 failed, 0 warnings.
  • Capped grids (Long Queries, newest 200 completions; Collection Log, newest 500 runs): a read that fills its cap names the oldest row it returned, also over a range the store covers; a read under the cap keeps the coverage notice, and a covered range under the cap shows none; the read's LIMIT and the notice's cap are the same constant; on a 1-hour range whose oldest row is later than the start the notice shows with no slack, and a 1-hour window makes no probe call. With the two notice calls, the LIMIT and the row time put back to the old shape, 6 of the new tests failed; after, DataStartBannerSurfaceTests 70 passed. The 432-test run of DataStartBanner*, QueryWindowTruncationTests, DisplayZoneTextFrameTests, CollectionHealthWindowTests, LongQuery* and two grid pin classes had one failure, the window census in QueryWindowTruncationTests (10 to 11 GetQueriesTabWindowUtc calls in ServerTab.Refresh.cs, for the Collection Log call), which is updated with its reason; the three affected classes then re-ran 100 passed, 0 failed, 0 warnings. After merging origin/dev (the shared cap step and the 90-minute window rule), all 14 banners were checked against both rules: none probes outside the shared step, and only Long Queries and the Collection Log read a capped page.
  • Duration Trends (DurationTrends_*, 3 tests). Three collectors at one run a minute over 24 hours (4,323 runs): the grid's page holds 500 of them and spans under 4 hours, and each collector's drawn line starts at the range's start and ends at its end. RED: with the chart fed the grid's page, as before, the test failed ("a line starts 2026-10-03T06:30:02, after the range's start 2026-10-02T09:16:02", about 2 h 46 min of the 24 h drawn). A 7-day range of one run a minute (10,081 runs, one of them 9,000 ms) comes back bucketed (under 2,000 points, every run counted once, no bucket before the range start); the 9,000 ms run is a point's height and its hover line reads "Slowest of N runs; average X ms" with X the bucket's real average. A source pin checks the refresh starts the chart's read beside the grid's and never hands the chart the grid's page.
  • Duration Trends hover after a gap (CollectorDurationHoverTests, 6 tests including the label and clear checks below). One collector, 20 buckets ten minutes apart, one 70-minute hole after the fifth (the line breaks once), bucket k holding k + 1 runs that averaged 50 + k ms. The chart is drawn and rendered, and the hover is asked with the mouse exactly on each bucket's point. RED on the lookup by position: bucket 10 said "Slowest of 12 runs; average 61 ms" where "Slowest of 11 runs; average 60 ms" was expected (the test stops at that first mismatch; the last bucket's position, 20 in a scatter of 21 points, runs past the 20 lines, so by the old lookup it had none). After the lookup by X: every bucket says its own, bucket 10 "Slowest of 11 runs; average 60 ms" and the last "Slowest of 20 runs; average 69 ms". The drawn scatter has 21 points (the 20 buckets and the one the break inserts): each of the 20 real points finds its own line by X and the inserted point finds none. A series registered without details keeps the three-line text (label, value, time).
  • Y axis label. RED: the chart's axis label was "Duration (ms)" and the test found no "Slowest run per bucket (ms)" in the update method's string literals. After: it reads "Slowest run per bucket (ms)" (checked in the method's source with comments ignored).
  • Empty range and the hover. RED: the hover's clear came after the empty-range return ("UpdateCollectorDurationChart clears the hover only after the empty range has returned"). After: the clear sits right after the chart's own clear, once, before that return. The update method is an instance method of the tab's control, so the order is pinned in its source (comments and string text ignored), and the clear itself is checked on a real chart: a hover that said a point's line says nothing after it (ClearingTheHover_LeavesItHoldingNothing).
  • This round: Lite, the Darling viewer, Lite.Tests and Darling.Tests built with 0 warnings, after merging origin/dev (no conflicts). Lite.Tests, the 18 classes that name the hover helper, the hover text, the detail lines, the Duration Trends chart or a file this change touches: 361 passed, 0 failed. Darling.Tests without a store (RepoFileAdoptionTests, DocCommentHygieneTests, CommentFilterAdoptionTests and the six classes that name the touched members): 194 passed, 0 failed.
  • Long Queries under its cap (2 tests). A first run at T0 = 48 hours ago stores a completion from T0 less 8 minutes; on a 7-day range the notice names T0 less 8 minutes. RED: before the change it named T0 ("Showing since 2026-10-01 09:16:01" where 2026-10-01 09:08:01 was expected). With no completion older than the first run it still names the run.
  • Wording (the probe's doc comment, the PR text): no test; the claim is checked against CollectorContext.EventFallbackWindow (10 minutes) and the Default Trace's first-run history.
  • Three source pins updated on purpose, each still requiring its call shape, now with the oldest-row argument (the shared step takes the oldest row a capped grid shows): TheSharedBannerRefresh_GoesThroughTheGuardedProbe, RefreshCappedGridBannerAsync_HandsTheDecisionThePickerZone_AndTheSharedProbingStep and TheRefreshHeaderAndTheTruncationBanner_UseTheTabsOwnClockAndZone. SurfacesWithoutANotice_KeepTheShapeThatNeedsNone no longer pins the Duration Trends chart (the tests above do).
  • Lite and Lite.Tests build with 0 warnings. After merging origin/dev (no conflicts) and the three items: DataStartBanner*, QueryWindowTruncationTests, StoredEventCopiesSweepTests, DisplayZoneTextFrameTests, LongQuer*, CollectionHealth*, CollectionLog*, AzureSqlDatabase*, the chart and axis classes and the other classes that name a file this change touches: 816 tests, 1 failure (the display-zone pin above, then updated); DisplayZoneTextFrameTests and DataStartBanner* re-run: 168 passed, 0 failed.
  • Not run: the full Lite.Tests suite, a look at the banners and the chart in the running app, and the Darling viewers and MCP tools (later waves).
  • Not added: a test that a bar nearer the cursor than the series' point carries no detail line. That code is the same as before (the line is dropped when the bar lowers the Y distance); only the lookup that finds the line changed.

Merge notes

  • All three Lite PRs add members to the same enum and arms to the same two maps. Mine sit in one block at each insertion point, opened by a comment naming group C. On a conflict keep both sides. The new QueryWindowRelationTimeColumn and QueryWindowRelationTimeIsServerLocal methods, and the probe's SQL and its server-local path, are the only edits outside those blocks.
  • If another PR's table is stamped something other than collection_time, it needs an arm in QueryWindowRelationTimeColumn; the updated pin test will say so.

CHANGELOG

No entry in this PR; the release owner adds it under [Unreleased].

Proposed entry:

  • Lite's Collection Log, System Events, Config Changes and Long Queries grids say where the data starts, and the Duration Trends chart draws the whole range ([Say where the data starts on every time-ranged tab, in Lite and both Darling viewers #4966]) - when the chosen range began before a server's data, these grids drew the shorter range with no notice, which read as a quiet period. The Collection Log, the eight System Events grids that read stored events, Default Trace, the three Config Changes grids and Long Queries now show "Showing since " beside the grid, worded at where the stored data begins: the first collection, or for the System Events and Default Trace grids the oldest stored event, which is older than the first collection when that run read events from before it. The Long Queries grid lists the newest 200 completions, so when the window held more it names the oldest one it shows; under that cap it names the oldest completion shown when that is earlier than the first collection, since a first run stores completions from just before itself. The Collection Log grid names the oldest of its newest 500 runs when the window held more. A quiet start, where the collector ran through the whole range but stored nothing near its start, shows no notice. The Collection Health Duration Trends chart was handed only the Collection Log grid's newest 500 runs, so on a long range it drew the newest slice and left the rest of its axis empty though the runs were stored; it now reads the whole range, draws each collector's slowest run per time bucket, its hover names the bucket's average and run count (also for the buckets after a gap in the line), and its Y axis reads "Slowest run per bucket (ms)". The Health Summary and the Corruption Events and Contention Events charts are unchanged.

Notes

  • Nothing from the three items or the hover, axis label and empty-range fixes is left over. Not run: the full Lite.Tests suite, a look at the chart and banners in the running app, and the Darling viewer's own Duration Trends chart (it has its own read and belongs to the Darling work).

…n Log, System Events, Config Changes and Long Queries grids (#4966)

The probe gains seven relations, each with its view and the collector whose runs show the store covered a quiet start, and a time column map for the three config snapshots, which are stamped capture_time. The tests pin, per surface, a notice for rows that start inside the range and no notice for a quiet start, plus the banner wiring and the surfaces that need none.
…ere the data starts when the range reaches before it (#4966)

Each of the 14 grids that read stored rows over the toolbar's range now has a Showing since banner beside it, refreshed after the rows are bound from the one method its read runs through, so the sub-tab switch, a range change and the Refresh button all reach it. The Health Summary (a fixed seven-day aggregate) and the Duration Trends, Corruption Events and Contention Events charts (axis pinned to the range) need none.
…nt, not the first run (#4966)

A server's first run stores the server's event history: rows whose event_time goes
back days, all stamped with that run's collection_time. The window-floor probe
measured collection_time for every event relation, found only the run, and the
banner said "Showing since <run>" above rows from before it. The System Events
grids that read system_health events and the Default Trace grid filter on
event_time, so the probe now measures that column for SystemHealthEvents and
DefaultTraceEvents. The collector-run part of the probe stays on collection_time,
and Long Queries stays on collection_time too, because its grid filters on it.

Tests: for each of the two relations, history reaching to H (S < H < T0) names H,
history reaching back to the range start (H <= S) shows no banner, and no stored
history names the first run. The seeder sets event_time and collection_time
separately for these tables, so the first case fails on the old column.

The relation-to-column pin now names event_time for the two relations and keeps
the archive's purge column (collection_time) pinned for them. StoredEventCopies's
sweep lists the probe's two view-name reads (system_health events and long query
completions), which the group C probe added without an entry.
…mes through the server's clock (#4966)

The Default Trace's event_time holds the monitored server's local wall-clock
time. Its grid converts each row to UTC through the server's clock, with the
offset in force at the row's own date. The data-start probe compared that column
with the UTC window as it was and returned the result as if it were UTC, so on a
server whose clock is not UTC both the banner's time and the before-or-after-the-range
test were off by the offset.

For that relation the probe now takes an optional ServerClock (falling back to
ServerTimeHelper.ActiveServerClock, as the grid does), reads the candidate rows over
the grid's pre-filter window (server-local bounds, an hour wider on each side),
converts each row to UTC, and uses the converted times for the earliest-row and
older-row checks, so the answer is exact across a daylight-saving change. The
collector's runs in v_collection_log are UTC, so the first run and the first row are
compared in C#, not in one LEAST. Every UTC relation, system_health's included (the XE
timestamp), keeps the single-query path.

Tests: on a clock 5 hours behind UTC the banner names the oldest event in UTC; on a clock
5 hours ahead an event before the start in UTC shows no banner; the mirror case shows the
banner; four US Eastern rows across the spring-forward and fall-back changes give the exact
UTC time and equal the oldest row the grid shows; the probe with no clock uses the active one.
# Conflicts:
#	Lite.Tests/DataStartBannerTests.cs
#	Lite/Services/LocalDataService.QueryWindowFloor.cs
…ts cap being a named constant (#4989)

GetRecentLongQueryCompletionsAsync now ends its statement with
LIMIT {LongQueryGridCap}, the one constant behind the read and behind the
grid's "Showing since" notice, so no literal LIMIT ends it. The terminal
literal-LIMIT roster in McpPayloadContractCensusTests drops its entry for
that read, and its summary now counts six remaining reads: five viewer-only
reads and the plan cache ceiling. The Collection Log grid's cap was already a
bound parameter, so it was never in the roster.
…range, Long Queries names the oldest completion shown, and first-run history depth is stated correctly (#4989)

The Duration Trends chart was handed the Collection Log grid's page (the newest 500 runs) while its X axis is pinned to the whole range, so a long range drew only the newest slice. It now reads per-collector buckets over the whole range (GetCollectorDurationTrendAsync, at the width the other trend charts use), draws each bucket's slowest run and names the average and the run count in the hover.

Long Queries under its cap now names the earlier of the coverage start and the oldest completion shown, as the Darling viewer does, since a first run stores completions from before itself and the grid shows their event times.

The doc comment on the probe's time column said a first run's event history goes back days; that holds for the Default Trace only, system_health and Long Queries reach about 10 minutes back.
…gap, its Y axis names the slowest run, and an empty range clears the hover (#4989)

The hover took its extra line from the point's position in the scatter, but the
line breaks at every collection gap by inserting a point of its own. After the
first break every bucket showed the NEXT bucket's runs and average, and the last
bucket showed none. The shared hover helper now keys the line by the X the point
is drawn at, and Lite builds the keys from the same X values the scatter is built
from, so a bucket finds its own line and the point a break inserts finds none.

The Y axis said "Duration (ms)" for a chart that draws each bucket's slowest run;
it now says "Slowest run per bucket (ms)". The empty-range path returned before
the hover was cleared, so a tooltip from the previous range could stay on an
empty chart; the hover is cleared before that return.
@erikdarlingdata erikdarlingdata changed the title Lite: Collection Log, System Events, Config Changes and Long Queries say where the data starts (#4966, group C) Lite: Collection Log, System Events, Config Changes and Long Queries say where the data starts, and Duration Trends draws the whole range (#4966, group C) Oct 3, 2026
@erikdarlingdata
erikdarlingdata marked this pull request as ready for review October 3, 2026 15:12
@erikdarlingdata
erikdarlingdata merged commit 07fd71b into dev Oct 3, 2026
23 of 24 checks passed
@erikdarlingdata
erikdarlingdata deleted the feature/4966-lite-c branch October 3, 2026 15:17
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