Fix 1000k counts and decimal digits of integers in number utilities

What does this MR do and why?

This fixes two small bugs in app/assets/javascripts/lib/utils/number_utils.js, each with the spec rows that reproduce it.

numberToMetricPrefix picked the k unit with number < MILLION and rounded afterwards, so 999950 to 999999 rounded to 1000.0 thousands and rendered as 1000k (or 1000K) instead of 1m, which is what 1000000c gives. It now rounds the value in thousands first and keeps the k unit only while the rounded value is below 1000. The function formats counts in the super sidebar, the groups and projects lists, the issuable tabs and the group and project delete modals, so a count in that range now shows 1m. GLQL's compact count formatter already rounds 999999 up the same way, to 1M (its spec row).

countFloatingPointDigits returned 4 for every non-zero integer (5, 12, '7'). splitDecimalNumber returns decimal: null when the value has no decimal part, and the function measured String(decimal).length, which is the length of the string "null". It now returns the length of the decimal part when there is one and 0 otherwise. Its only caller, metric_tile.vue, calls it only for non-integer values, which have a decimal part unless written in exponent notation (1e-7), so in practice nothing renders differently there; the fix keeps the exported utility correct for other callers.

Behaviour change: numberToMetricPrefix renders values from 999950 to 999999 as 1m instead of 1000k, and every other value as before. Values from 999950000 up still render in millions (1000m, 1500m and so on), because the function has no unit above m; I left that alone.

References

No issue tracks these two bugs. The spec rows and the screenshots below show them on master.

Screenshots or screen recordings

Explore > Projects on GitLab CE 19.5.0 (the official Docker image), signed out, with the star counts of three projects set in the database to 1000000c, 999950 and 999949. The After image is the same page with the served bundle's numberToMetricPrefix changed in the browser the way this MR changes the source; it is not a build of this branch.

Before After
Star counts 1m, 1000k and 999.9k Star counts 1m, 1m and 999.9k

How to set up and validate locally

  1. Run yarn jest spec/frontend/lib/utils/number_utils_spec.js. All 93 examples pass.
  2. Run git checkout master -- app/assets/javascripts/lib/utils/number_utils.js and run the spec again. Five of the new rows fail: countFloatingPointDigits returns 4 for 5, 12 and '7', and numberToMetricPrefix returns 1000k for 999950 and 999999.
  3. Run git checkout HEAD -- app/assets/javascripts/lib/utils/number_utils.js to restore the fix.
What I ran

On master at f0464c04, with Node 22.23.1 and the frozen yarn.lock:

  • spec/frontend/lib/utils/number_utils_spec.js with master's number_utils.js: 5 failed and 88 passed, each failure on the defect itself (Received: 4 and Received: "1000k"). With the fix: 93 passed.
  • That spec and the specs of every caller of the two functions, CE and EE, with the frontend fixtures the package registry holds for a master commit two commits earlier: 21 suites and 563 examples pass. They include tabs_with_list_spec.js, groups_list_item_spec.js, projects_list_item_spec.js and organization_group_stats_spec.js, which load generated fixtures, and super_sidebar/utils_spec.js, sidebar_menu_spec.js, both delete modal specs, issuable_tabs_spec.js, metric_tile_spec.js, delete_modal_secrets_count_spec.js and the observability usage specs.
  • Three mutants of the fix (an integer fallback of 1, <= instead of < against 1000, and the old unrounded condition) each fail the new rows.
  • yarn run lint:eslint and Prettier on the two changed files are clean, and scripts/lint/commit_linter.rb accepts the commit message.

The new rows without the fix, condensed from the Jest output:

passed  returns 999.9k given 999949
failed  returns 1m given 999950            Expected: "1m"  Received: "1000k"
failed  returns 1m given 999999            Expected: "1m"  Received: "1000k"
failed  when called with 5 it returns 0    Expected: 0     Received: 4
failed  when called with 12 it returns 0   Expected: 0     Received: 4
failed  when called with 7 it returns 0    Expected: 0     Received: 4

Tests:       5 failed, 88 passed, 93 total

With the fix:

Tests:       93 passed, 93 total

I found these while maintaining gitlab-mcp-server; its upstream-bugs.md records everything done on its dependencies and sibling projects.

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.

Merge request reports

Loading
Loading