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 theupstreamRepositoriesCountprop, anisVirtualbranch ofstats()that returns the single Repositories figure, a pluralizedrepositoriesLabel, and ashowStatscomputed that hides the block on a null count.repository_detail.vue: adds theupstreamRepositoriesCountcomputed (null unless the virtual list has loaded) and passes it to the sidebar.locale/gitlab.pot: regenerated. The newn__call gives a plural form toArtifactRegistry|Repository, the singular msgid the upstream table already uses for itsnamecolumn header (constants.js:497). The pluralArtifactRegistry|Repositoriesis 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 withhideStatshides it too, no connection or caching) and count-passing coverage inrepository_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.jsOutput (✅ )
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 totalStep 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.jsOutput (✅ )
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.potOutput (✅ )
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-texticon), 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.