monolith/S05 virtual Step 5: Virtual sidebar stats

What this does

Renders the virtual repository sidebar stats as the Repositories figure alone, taken from the loaded upstream list length. Step 5 of the monolith/S05 virtual repository detail plan, dark behind artifact_registry_ui.

On a populated virtual repository the stats block shows the upstream count and nothing else, whatever sizeBytes, downloadsCount, or artifactsCount the response carries. The detail view passes the count (null while the list is loading or after it failed), and the sidebar hides the whole stats block on a null count so a failed read never reads as a repository with zero sources. When the list is empty the block hides through the existing hideStats (Step 6 covers that state). Hosted and remote stats are unchanged.

The Figma frame (589-36301) renders Size and Downloads here too, but the S05 spec overrides it: Size is defined as zero and Downloads is not written on any kind, so both are omitted and the count renders alone. The Repositories figure uses the doc-text icon the design shows.

Closes #628666 (closed)

Related to #628475 (closed)

Changes

  • repository_sidebar.vue: adds the upstreamRepositoriesCount prop, an isVirtual branch of stats() that returns the single Repositories figure, a pluralized repositoriesLabel, and a showStats computed that hides the block on a null count.
  • repository_detail.vue: adds the upstreamRepositoriesCount computed (null unless the virtual list has loaded) and passes it to the sidebar.
  • locale/gitlab.pot: regenerated. The new n__ call gives a plural form to ArtifactRegistry|Repository, the singular msgid the upstream table already uses for its name column header (constants.js:497). The plural ArtifactRegistry|Repositories is a separate msgid and already existed as the repository list title and page heading (constants.js:19).
  • Specs: virtual figure coverage in repository_sidebar_spec.js (figure alone, list length, mismatched counter, singular label, null hides the block, a zero count with hideStats hides it too, no connection or caching) and count-passing coverage in repository_detail_spec.js (loaded count, 20-vs-artifacts mismatch, null while loading, null on failure, null on hosted and remote).

Note on the plan: the plan lists constants.js for the label. No stat label lives in constants.js today (the sibling figures compute pluralized labels inline with n__), and inlining is the only way to get the promised new pot string, so this step follows the sibling pattern and leaves constants.js untouched. The stories and mock_data.js need no change either: the existing virtual stories render the new figure through the count the detail view now passes.

How to set up and validate locally

This is a dark, mock-driven frontend change. The behavior is proven by the Jest suites; the visual states are drivable in Storybook through the existing virtual stories (VirtualRepository, VirtualRepositoryAtCapacity, VirtualRepositoryWithoutUpstreams, VirtualUpstreamsUnavailable).

Step 1 — Unit specs for the sidebar and detail view

node_modules/.bin/jest --config jest.config.js \
  ee/spec/frontend/packages_and_registries/artifact_registry/repositories/detail/repository_sidebar_spec.js \
  ee/spec/frontend/packages_and_registries/artifact_registry/repositories/detail/repository_detail_spec.js
Output (✅)
PASS ee/spec/frontend/packages_and_registries/artifact_registry/repositories/detail/repository_sidebar_spec.js
PASS ee/spec/frontend/packages_and_registries/artifact_registry/repositories/detail/repository_detail_spec.js

Test Suites: 2 passed, 2 total
Tests:       175 passed, 175 total

Step 2 — Lint the changed JS/Vue

node_modules/.bin/eslint \
  ee/app/assets/javascripts/packages_and_registries/artifact_registry/repositories/detail/repository_sidebar.vue \
  ee/app/assets/javascripts/packages_and_registries/artifact_registry/repositories/detail/repository_detail.vue \
  ee/spec/frontend/packages_and_registries/artifact_registry/repositories/detail/repository_sidebar_spec.js \
  ee/spec/frontend/packages_and_registries/artifact_registry/repositories/detail/repository_detail_spec.js
Output (✅)
ESLINT_EXIT=0
(no lint problems)

Step 3 — Prettier formatting

node_modules/.bin/prettier --check <the four files above>
Output (✅)
Checking formatting...
All matched files use Prettier code style!

Step 4 — Regenerate the translations

tooling/bin/gettext_extractor locale/gitlab.pot
git diff locale/gitlab.pot
Output (✅)
 msgid "ArtifactRegistry|Repository"
-msgstr ""
+msgid_plural "ArtifactRegistry|Repositories"
+msgstr[0] ""
+msgstr[1] ""

Evidence

Rails console

N/A. No client change.

GraphiQL

N/A. No GraphQL change; this step consumes the existing upstreamRepositories field.

Screen recordings

Recorded in the GDK against this branch's build, with the Artifact Registry HTTP boundary stubbed. AR does not serve virtual repositories yet (the listUpstreamRepositories route is unimplemented; Phase 6 step 40, gitlab-org/ops/artifact-registry!2735 (merged), is not merged), so a real AR renders the not-found page. The stub stands in for that boundary only. The Vue, resolver, and client code exercised are this branch's.

The recording walks four states:

  • Populated virtual (my-virtual, 4 upstreams): the sidebar renders the Repositories figure alone (4 Repositories, doc-text icon), with no Size, Downloads, or Packages.
  • Empty virtual (payment-core): the stats block is hidden.
  • Failed upstream read (virtual-unavailable, upstream list returns 500): the stats block is hidden.
  • Hosted (my-hosted, regression): Size, Downloads, and Packages render unchanged.
Edited by Fiona McCawley

Merge request reports

Loading
Loading