Add the Overview and Referrers tabs to the manifest page

What does this MR do and why?

Adds a tab bar to manifest_detail.vue with two tabs, Overview and Referrers. Both are deliberately empty here. Step 5 fills Overview with the pull snippets, step 8 fills Referrers with its table. This MR is the structure and the routing only.

The active tab lives in a tab query parameter rather than component state, so a tab is shareable by URL and the back button works. Selecting a tab pushes the query instead of holding local state.

tab value Renders
absent Overview
empty string Overview
overview Overview
referrers Referrers
anything unrecognised Overview

referrersCount was added to the get_manifest GraphQL query selection so the Referrers tab can carry its count badge. The local mock seed already carried the field, so no seed change was needed.

Live region names the active tab

The page announcement now names the active tab, matching the pattern already on the Maven/npm version page. Two translated strings changed shape: ArtifactRegistry|Manifest %{digest} of %{name}. became ArtifactRegistry|%{tab} tab for manifest %{digest} of %{name}., and the no-image variant alongside it changed the same way.

Zero renders as 0, not hidden

A zero count renders as an exact 0 rather than being hidden. The merged manifest-read contract makes the four manifest counts live and exact, and on a remote repository referrers_count is always 0. That zero is a real reading, not a missing value, so hiding it would assert something the data does not say.

Every numeric count is paired with tabCountSrText. GlTab renders its count badge with aria-hidden="true" and warns when a count arrives without screen-reader text. Confirmed in the accessibility tree: the tab's accessible name reads Referrers 1 referrer, and 0 referrers on a manifest with none.

TABS is a flat list, not a map

The sibling Maven/npm page (version_detail.vue) keys its tabs by format. TABS here is a flat list instead, because Docker and OCI carry the same two tabs and there is no format axis to key off of.

What's not here

The design prototype shows three tabs: Overview, Manifest, Referrers. This ships two. The raw Manifest payload tab is withdrawn by the phase plan, because its backing route serves raw bytes rather than a JSON resource, in an area ADR-009 leaves unreconciled. That withdrawal is recorded on the plan MR, not decided here.

References

Screenshots or screen recordings

Docker index manifest, Overview active, with the Referrers count badge. There is no meaningful "before" — the page had no tab bar at all.

Before After
No tab bar s06p2-step2-docker-index-overview

How to set up and validate locally

The manifest detail page is not reachable by clicking yet — the container row link on the manifests table is step 11, which is held until the GraphQL integration lands. So reach it by URL.

  1. Enable the flags in the rails console:

    Feature.enable(:artifact_registry_ui)
    Feature.enable(:org_stage_experimental)
  2. The seeded container repositories are docker-images and oci-artifacts. Manifest digests are derived rather than listed, so use one of these, which are stable against the local seed:

    • Docker index, one referrer: /o/default/-/artifact_registry/acme/repositories/docker-images/73f2a86e-73f2-a86f-73f2-a87073f2a871/manifests/sha256%3A2ba136e32ba136e42ba136e52ba136e62ba136e72ba136e82ba136e92ba136ea
    • Docker single-image child, no referrers: /o/default/-/artifact_registry/acme/repositories/docker-images/73f2a86e-73f2-a86f-73f2-a87073f2a871/manifests/sha256%3A791e860f791e8610791e8611791e8612791e8613791e8614791e8615791e8616
    • OCI index, one referrer: /o/default/-/artifact_registry/acme/repositories/oci-artifacts/36c00923-36c0-0924-36c0-092536c00926/manifests/sha256%3A1460bea91460beaa1460beab1460beac1460bead1460beae1460beaf1460beb0
  3. Confirm both tabs render and both panels are empty, that clicking Referrers appends ?tab=referrers, that loading with ?tab=referrers selects it, and that ?tab=bogus falls back to Overview.

Verification

Driven in the GDK with all three URLs above, on Docker and OCI, index and single-image child. Zero console errors on every load. Confirmed: the tab bar renders Overview and Referrers and no third tab; clicking Referrers appends ?tab=referrers; loading with ?tab=referrers selects it; ?tab=bogus falls back to Overview; the count badge reads 1 on an index with one referrer and an exact 0 on the child with none.

The manifest detail spec passes 53 tests on Vue 2 and 53 on Vue 3 (both run). The full artifact registry Jest suite passes 64 of 65 suites; repository_detail_spec.js fails with 55 failures. That failure is pre-existing: I ran the same spec at the base commit with all changes stashed and got the identical 55 failures, so it is unrelated to this change.

ESLint clean at --max-warnings 0, Prettier clean, and locale/gitlab.pot regenerated with the gettext extractor.

No changelog entry — the feature is dark behind artifact_registry_ui and unreleased.

Stacked

Rebased onto master on 2026-09-10. Step 1 (!253776 (merged)) was squash-merged, so this branch was cut off its old tip with git rebase --onto master rather than a plain rebase — a squash leaves no matching patch ids, so a plain rebase would have tried to replay Step 1's commits. This MR now targets master directly and carries only its own commit.

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 Zack Cuddy

Merge request reports

Loading
Loading