Add tag badges to the manifest detail header

What does this MR do and why?

Renders one badge per tag in the manifest detail page header, between the H1 short digest and the existing kind badge, matching where the design prototype places them. Tag badges use the info variant and a monospace class; the kind badge stays neutral. An untagged manifest — pulled by digest alone, so there's no tag row to render — shows no badges at all. tags was added to the get_manifest query selection.

Render order follows the server, not a view-side sort

The view renders tags in the order they're served and does not re-sort or re-cap them. The merged contract serves tags name ascending and bounds the list by container.manifest_max_tags (1,000). Re-sorting in the view would hide a server that stopped sorting; re-capping would duplicate a bound the server already applies.

Seed fidelity gap closed

That decision exposed a gap in the local Apollo mock: it seeded tags by slicing a fixed TAG_NAMES list, which isn't alphabetical, so the seed served them unsorted. mock_artifacts.js now sorts them, and a new assertion in mock_artifacts_spec.js pins that every ladder's tags come back name ascending — without it, an unsorted seed would hide a view that forgot to render in order.

One Step 1 test updated

manifest_detail_spec.js had asserted the kind badge was the first GlBadge on the page, which is no longer true now that tag badges precede it. It now asserts the kind badge is a badge and sits outside the heading, which was the test's actual intent. A new test pins the ordering — tag badges then the kind badge — since that ordering is what the design specifies and what could silently regress.

References

Screenshots or screen recordings

There's no meaningful "before" — the header carried no tag badges.

Every tag fits. Five or fewer tags render inline, with no overflow affordance:

Tag badges on a tagged index manifest

More tags than the header shows. An index carrying 11 tags renders the first five and collapses the remaining six:

Five tag badges followed by a plus six more control

The collapsed tags, opened. Activating +6 more reveals the rest in an "All tags" popover, so no tag is dropped from the page:

An All tags popover listing the six collapsed tags

The overflow shots were taken against a locally widened tag seed — the committed seed offers at most five tag names, so the collapsed state cannot be reached on a stock GDK. The ManyTags and LongTagName Storybook stories added in this MR cover it without that patch.

How to set up and validate locally

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

Image ids must come from the repository's own artifact list, since they're server-resolved, while manifest digests are derived from whatever image id they're handed.

  1. Enable the flags in the rails console:

    Feature.enable(:artifact_registry_ui)
    Feature.enable(:org_stage_experimental)
  2. Visit the tagged index: /o/default/-/artifact_registry/acme/repositories/docker-images/b7dad7c9-c3f8-9264-5f55-3619a3c720a4/manifests/sha256%3A5e30d0925e30d0935e30d0945e30d0955e30d0965e30d0975e30d0985e30d099

  3. Visit the untagged single image: /o/default/-/artifact_registry/acme/repositories/docker-images/b7dad7c9-c3f8-9264-5f55-3619a3c720a4/manifests/sha256%3A2bae1fbf2bae1fc02bae1fc12bae1fc22bae1fc32bae1fc42bae1fc52bae1fc6

Verification

Driven in the GDK. The tagged index renders five badges reading latest rc1 stable trixie v1 — name ascending — followed by the grey Index · 3 platforms kind badge. The untagged single-image child renders zero tag badges with its Image kind badge intact. Zero console errors on both.

Full artifact registry Jest suite on both Vue 2 and Vue 3: 2160 passing, 64 of 65 suites green. repository_detail_spec.js fails with 55 failures; verified pre-existing by running it at the base commit with all changes stashed and getting the identical 55 failures.

ESLint clean at --max-warnings 0, Prettier clean. No new translated strings — tag names are raw values, so locale/gitlab.pot is untouched.

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