Add the manifests table to the artifact version list
What does this MR do and why?
Note
Targets !250074 (merged), which in turn targets !249937 (merged). Both merge first.
This change is behind the feature flag :artifact_registry_ui
The previous step added a versions table to the artifact version list page for Maven and npm, leaving Docker and OCI rendering a header and nothing else. A container's versions are its manifests, a different contract resource read from a different endpoint. This fills that gap, so all four formats render content, with a manifests table of three columns: Digest, Size, and Published.
| Design column | What happened |
|---|---|
| Digest | Ships — 12 characters, no sha256: prefix, as the design renders it |
| Size | Ships |
| Published | Ships |
| Type | Next step, once media_type, artifact_type, and subject_digest are read |
| Tags | Phase 2 |
| Referrers | A later step ships the referrer preference; the count column is not in the contract |
| Row menu | A later step ships View pull command and Copy digest |
| Platforms | Not in the contract — a manifest carries no platform triple |
| Downloads | Not in the contract — no download count |
| Source | Not in the contract for a manifest, and descoped for a version — Source is out of the beta |
A version does carry created_by, project_id, and git_commit_sha, so a Source column was
once planned for the versions table. That has since been descoped: Source is out of the beta, so
neither table gets one.
Worth noting on Size: the contract states it is the whole manifest tree rooted at that manifest, computed at push time, and warns it can double-count a blob shared with another manifest. It is rendered per row and never totalled.
Changes
-
New manifests query.
graphql/queries/get_artifact_manifests.query.graphql, the counterpart of the versions document, repeatingartifactIdon the@clientparent for the same variable-pruning reason, and added tographql/queries_spec.js's guard table. -
New types.
ArtifactRegistryManifest(id,digest,size,createdAt) andArtifactRegistryManifestConnection, plus amanifestsfield onArtifactRegistryImage. Declared once, unlike the previous step'sversions, because an image is a plain type rather than a union.sizeis typedString!because the contract types it int64 and GraphQL's BigInt scalar serializes as a string, which is the shapehumanSizealready expects. -
Mock resolver. A
manifestsresolver on the image type, reusing the existingdelay,paginate, andartifactKeyhelpers. The previous step'sversionsNewestFirstis renamednewestFirstand shared, since Artifact Registry lists both resourcessort=created_at&order=descby default. -
Seed data. A manifest ladder on each seeded image, held under
storedManifestsrather thanmanifests, or Apollo falls back to writing the bare array where a connection belongs. Digests are generated as 64 hex characters so they satisfy the contract's^sha256:[0-9a-f]{64}$pattern; the design proposal's mock digests are not hex. Manifest ids come from a third sequence of their own, so adding them cannot renumber the artifact ids the repository table links to. -
New table.
repositories/versions/manifests_table.vue— the shortened digest as monospace text beside aClipboardButtoncarrying the full canonical digest, size through the existinghumanSize, published throughTimeAgoTooltip. -
A new
shortDigesthelper, because nothing existing fits. The monolith already shortens digests in four places, and they disagree:Site Characters kept Container registry 7 Harbor 7 Dependency proxy 7 Google Artifact Registry 12 truncateShain~/lib/utils/text_utility.jscannot serve: it takes the first 8 characters of whatever it is handed and does not strip an algorithm prefix, so it returns'sha256:'. The new helper follows Google Artifact Registry's 12 characters, which is also what the design renders, and splits on the:rather than assuming an offset of 7, so a digest carrying some other algorithm still reads as a digest. -
Format switch.
versions_section.vuetakes a format and renders the versions or the manifests table, the way the mergeddetail/artifacts_section.vuetakes a format and hands it to one table. Its row prop is now format-neutral. -
One connection query, not two. The previous step gave the page a versions query skipped for containers. A page is either versions or manifests and never both, which is the shape the merged
repository_detail.vuealready solves with one query whosequery()returns the images or the packages document by format. That block is generalized the same way rather than duplicated: one document switch, one error flag, one loading computed, oneskip(). Every populated page now reads a connection, so the terminal announcement is always the version-list one, and the now-dead"Artifact details for %{name} loaded."string is removed. -
Specs. The new table, the section's format switch, the switching query across all four formats, the resolver's ordering and digest form, the new helper, and a seed guard that every manifest digest is distinct.
Screenshots or screen recordings
How to set up and validate locally
- Enable the flag:
Feature.enable(:artifact_registry_ui). - Visit
/o/<organization>/-/artifact_registry/acme/repositories. - Open
payment-service(Docker), thenoci-artifacts(OCI), and click an artifact name in each. Confirm the manifest table renders newest-first with a 12-character digest, a human-readable size, and a relative publication time. - Click a copy button and confirm the clipboard holds the full
sha256:digest rather than the shortened form. - Open
payment-core(Maven) andui-components(npm) and confirm their versions table still renders unchanged — that is the regression risk of generalizing the previous step's query.
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.
