Wire date range filter to DAP Impact dashboard panels

What does this MR do and why?

The DAP Impact analytics dashboard (/explore/analytics_dashboards/dap_impact) had its date range filter turned off. This MR turns it on, but enabling it alone was not enough: the picker renders and changes nothing on any panel. So this MR also makes every panel respond to it.

Two independent gaps caused this, both confirmed in the code:

  1. The four GLQL stat panels hardcoded their window in the query itself (timestamp >= -30d). The GLQL data source at app/assets/javascripts/analytics/analytics_dashboards/data_sources/glql.js passed the query string straight through and ignored the filters argument that analytics_dashboard_panel.vue hands every data source.
  2. The "Where credits went (WIP)" BarChart panel uses the code_suggestions_acceptance_by_language data source, which read its range only from the panel's own query.dateRange and never looked at filters.

Four changes fix this:

  1. app/assets/javascripts/analytics/analytics_dashboards/data_sources/glql.js resolves the dashboard date range into the query string via two placeholders, %{startDate} and %{endDate}. A GLQL query names its own date field (timestamp, merged, created, depending on the object queried), so the panel declares where the range belongs rather than the data source guessing the field name. A query with no placeholders is returned untouched, so GLQL panels on dashboards with no date filter keep the window their own query sets. Bounds fall back in order: the dates the filter supplies, then the selected option's own dates, then the last 30 days. That last fallback matters because the custom option carries no dates of its own, and an unsubstituted placeholder would reach the GLQL compiler as a literal and fail the whole panel.
  2. ee/app/assets/javascripts/analytics/analytics_dashboards/data_sources/code_suggestions_acceptance_by_language.js now takes filters, with the dashboard filter's option winning over the panel's own default, and the filter's dates winning for a custom range. This follows the shape already used by app/assets/javascripts/analytics/analytics_dashboards/data_sources/mean_time_to_merge.js. The other two dashboards that use this data source (duo_and_sdlc_trends and the AI impact dashboard) configure no filters at all, so they are unaffected.
  3. app/assets/javascripts/explore/analytics_dashboards/pages/details.vue seeds the page's filters from the dashboard's own filter config on load, and restores that seed on reset instead of clearing to an empty object. The date range picker renders the configured default in its own local state without emitting it, so before this the page held no date range until the user touched the picker, and a panel would resolve its own default window instead. That was a latent trap: changing defaultOption in a dashboard YAML would silently show a different range than the picker names on first load. The EE dashboard route already seeds its filters this way via buildDefaultDashboardFilters, so this brings the explore route in line.
  4. ee/lib/gitlab/analytics/dashboards/system/dap_impact.yaml enables the filter (enabled: true, defaultOption: 30d, options: 7d, 30d, 90d, 180d, custom, numberOfDaysLimit: 180) and rewrites the four GLQL panel queries from timestamp >= -30d to timestamp >= "%{startDate}" and timestamp <= "%{endDate}". The option list and day limit follow the shape used by the DORA metrics and merge request analytics dashboards. The 30d default matches the window the queries hardcoded before, so a first load shows the same data it always did.

One detail worth stating once: GLQL reads an absolute date bound as the whole day. Verified by compiling through the real WASM build: timestamp <= "2026-09-02" compiles to timestampTo: "2026-09-02 23:59". So the range needs no end-exclusive adjustment, unlike the GraphQL-backed sources that add a day to the end date.

References

https://gitlab.com/gitlab-org/gitlab/-/work_items/623421+

How to set up and validate locally

  1. Visit /explore/analytics_dashboards/dap_impact.
  2. Select a group. Every panel on this route is namespace scoped, and nothing renders until a namespace is chosen.
  3. Confirm the date range picker shows "Last 30 days".
  4. Change it to "Last 7 days" and confirm all five panels change.
  5. Pick a custom range and confirm all five panels change again.

If you edit the dashboard YAML while testing, run gdk restart rails-web afterwards: SystemDashboardsLoader memoises the parsed dashboard, so changes are not picked up until the process restarts.

Tests

  • spec/frontend/analytics/analytics_dashboards/components/data_sources/glql_spec.js: 13 tests. New cases cover resolving the placeholders from a selected option; falling back to the last 30 days for no filters, an empty filter set, and an unknown option; taking the filter's dates for a custom range; falling back for a custom range with no dates; substituting an open-ended range that sets only a start; substituting every occurrence of a placeholder; and leaving a query with no placeholders untouched.
  • spec/frontend/explore/analytics_dashboards/pages/details_spec.js: the shared loader stub now emits loaded the way the real loader does, so the spec exercises seeding. New cases cover following the dashboard's configured option, falling back to the last 30 days for an unknown option, and seeding nothing when the dashboard turns the filter off. One existing assertion changed from an empty filters object to the seeded default, because that is the new behaviour.
  • ee/spec/frontend/analytics/analytics_dashboards/components/data_sources/code_suggestions_acceptance_by_language_spec.js: new cases for the filter option beating the panel default, the filter's dates for a custom range, and the panel default surviving when no filter is applied.

Verification

  • jest spec/frontend/analytics/analytics_dashboards spec/frontend/explore/analytics_dashboards ee/spec/frontend/explore/analytics_dashboards spec/frontend/analytics/shared spec/frontend/glql: 2375 tests passing across 166 suites.
  • Schema validation via a Rails runner: schema_errors_for returns OK for the dashboard YAML, and SystemDashboardsLoader.find_by_slug("dap_impact") still resolves. This matters because the loader rescues and swallows schema errors, so a bad dashboard would silently disappear from the list rather than error.
  • End to end check through the real GLQL WASM compiler: the resolved query compiles for the default 30 day window, for a 7d selection, and for a custom range, producing timestampFrom and timestampTo bounds that match the selection.
  • ESLint and Prettier on all changed JS and Vue files: clean.
  • Mutation checks, three of them: making the GLQL data source ignore filters fails 8 tests; removing the seeding in details.vue fails 3; making the EE data source ignore filters fails 2.
  • 4 suites in the analytics paths fail to load locally for an unrelated reason: missing GraphQL test fixtures, because bin/rake frontend:fixtures has not been run for them in this checkout. They are data source specs that do not import anything changed here.
  • No manual browser check was run by the author of this MR. The reviewer should use the validation steps above.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Brandon Labuschagne

Merge request reports

Loading
Loading