Bump GLQL to 0.39.0

What does this MR do and why?

Bumps GLQL gem and npm package to 0.39.0. Integration work tracked in glql#229 (closed).

Presenter changes (app/assets/javascripts/glql/):

  • Chart labels flatten list-valued parameters, so userTier(thresholds=[4, 25, 100]) renders as "User tier (4, 25, 100)" instead of "(4,25,100)".
  • A Group label formatter is registered for chart dimensions. Without it, unregistered object types label as "" and every group collapses into one series. It prefers fullName, then fullPath, to match the table's link presenter.
  • Fixed-day buckets (30d) are labelled as a date range, same as weekly buckets, and the multi-year label check extends the last bucket by its span.
  • Table columns of Group type sort by full name; the sorter had no Group entry, so clicking the new group dimension's header did nothing.
  • The DuoWorkflows totalCount stat description matches the backend field description, "Total number of flows, optionally filtered by status." (pot regenerated).

Docs:

  • duo_workflows.md: userTier dimension, flowTypesUsed/activeDays filters, status parameter on totalCount, group dimension, and examples.
  • ai_usage_events.md: group dimension.
  • _index.md: list values in field parameters, fixed-day granularities, the origin parameter with a two-period example, and the operators behaviour change below.
  • Every analytics source page: wider granularity wording.
  • doc/api/glql.md: the new schema parameter kinds and attributes.

Deliberately left out: the DAP Impact dashboard changes listed in glql#229 (closed) (group comparison panel, status tiles, origin-based period comparison). Those will be a separate MR.

Behaviour changes to call out

  1. Compile error for = combined with another comparison on the same date field, for every data source and mode, standard mode included. Example: type = Issue and created = 2024-01-01 and created > 2023-01-01 now returns an error. Before, only one of the two conditions reached the query. Existing GLQL blocks written this way will show the error after this bump. Source: glql!516 (merged).

Observed, not changed: labelWithParameter appends every resolved parameter value, so an unaliased group dimension is titled "Group (1)" from the defaulted depth, and an unaliased created(granularity=30d, origin=2026-07-16) is titled "Created (30d, 2026-07-16T00:00:00Z)" in both chart axis titles and table headers. Same mechanism as created(weekly) today; the docs examples alias these fields.

Follow-ups (not in this MR)

  • Chart builders use the dimension label as the series identity. Rows that share a label, including several group: null rows from the new group dimension, overwrite each other, so counts of 12 and 7 display as 7. Needs identity separated from label for UserCore, Project and Group, plus an explicit policy for unresolved rows, since summing is wrong for unique counts, averages and quantiles. Tracked in #630162.
  • userTier values render raw (tier_0, tier_1, ...). A human label such as "4-24" needs parameters.thresholds in both the table presenter and the chart label formatter, or tables and charts disagree. The docs row explains the tier numbering.
  • Fixed-day bucket labels use calendar dates and ignore the time of day of origin. Showing the exact boundary would mean reading parameters.origin in the label formatter, since the bucket start the engine returns is date-only. No issue filed; the docs state the limitation.

Screenshots

Verified on GDK with a locally built 0.39.0 wasm package, against local ClickHouse data. Every GLQL example added to the docs compiles with the 0.39.0 gem through the same path as POST /api/glql and renders without errors on GDK.

GLQL Screenshot
title: "Duo workflow users by activity tier (last 90 days)"
display: table
mode: analytics
query: type = DuoWorkflow and group = "gitlab-org" and created > -90d
dimensions: userTier(thresholds=[4, 25, 100]), flowType
metrics: totalCount, usersCount
sort: userTier asc

1_usertier_table

title: "Duo workflows waiting on the user, by flow type (last 90 days)"
display: columnChart
mode: analytics
query: type = DuoWorkflow and group = "gitlab-org" and created > -90d
dimensions: flowType
metrics: totalCount(status=["paused", "input_required"])
sort: flowType asc

2_status_count_chart

title: "AI usage events by group"
display: columnChart
mode: analytics
query: type = AiUsageEvent and group in ("gitlab-org", "gitlab-duo", "toolbox") and timestamp > -365d
dimensions: group
metrics: totalCount
sort: totalCount desc

3_group_chart

title: "AI usage events per 30 days"
display: columnChart
mode: analytics
query: type = AiUsageEvent and group = "gitlab-org" and timestamp > -120d
dimensions: timestamp(30d)
metrics: totalCount
sort: timestamp asc

4_fixed_day_chart

title: "AI usage events, two 30-day periods anchored at 2026-07-16"
display: table
mode: analytics
query: type = AiUsageEvent and group = "gitlab-org" and timestamp >= 2026-07-16 and timestamp < 2026-09-14
dimensions: timestamp(granularity=30d, origin=2026-07-16)
metrics: totalCount, usersCount
sort: timestamp asc

5_anchored_table

How to set up and validate locally

  • With the dap_impact_v1 feature flag enabled:

    mode: analytics
    query: type = DuoWorkflow and group = "<your-group>" and created > -90d
    dimensions: userTier(thresholds=[4, 25, 100]), flowType
    metrics: totalCount, usersCount
    sort: userTier asc

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Related to glql#229 (closed)

Edited by Daniele Rossetti

Merge request reports

Loading
Loading