Bind the artifact registry detail connections to the schema
What does this MR do and why?
This MR connects the Artifact Registry repository detail page to the real GraphQL schema, so the frontend reads its artifact list from the server instead of from local mock resolvers.
It adds a lastDownloadedAt field to three GraphQL types: ArtifactRegistryImage, ArtifactRegistryMavenPackage, and ArtifactRegistryNpmPackage. The field is Types::TimeType, nullable, and marked experiment: { milestone: '19.4' }. The matching Ruby value objects in ee/lib/artifact_registry/ gain a last_downloaded_at reader. Each reader coerces the ISO8601 string through the existing TimeCoercion module, so an absent or unparseable timestamp reads as null instead of raising.
It also changes ArtifactRegistryNpmPackage.versionsCount from non-nullable to nullable. Artifact Registry sends no versions_count for a package that belongs to a remote repository. A non-nullable field with no value nulls the entire node and errors the read, so a remote npm repository previously returned a page of nulls with GraphQL errors. The field is nullable, not defaulted to zero, because zero would wrongly claim the package has no versions. This is a relaxation, non-null to nullable, which the GraphQL guidelines do not treat as a breaking change. The field is experiment status and sits behind the disabled artifact_registry_ui flag.
On the frontend, get_repository_images.query.graphql and get_repository_packages.query.graphql previously resolved their artifact connections through a local Apollo client layer, the @client directive plus mock resolvers, because the schema did not carry the connections yet. The schema carries them now, so both documents drop the @client directive and read from the server. Paging variables (first, last, before, after) now travel to the server, so a shared URL that contains a cursor opens the page it names. The local mock resolvers for those connections are removed, along with now-unreachable mock resolvers for the detail read's artifactsCount, createdAt, createdBy, and updatedBy.
A null connection now renders the page's not-found state instead of the error alert inside the artifact table region. Artifact Registry resolves the connection to null both when a repository is deleted between the two reads and when it silently refuses the read (401, 403, 404). Neither case is a service outage. A read that actually errors still shows the alert.
The MR adds a new JavaScript fixture spec, ee/spec/frontend/fixtures/artifact_registry/repository_artifacts.rb, which posts both documents against the real schema with Artifact Registry stubbed at the HTTP boundary. The packages document has a second fixture example for a remote npm repository, so its JSON pins versionsCount as null. The page's Jest spec renders the JSON those fixtures produce for all four repository formats, so a change to a connection's field set fails the spec rather than drifting. The MR also adds a :js browser example to ee/spec/features/artifact_registry/repositories_spec.rb, asserting the artifact rows a repository's format resolves.
Finally, the sidebar divider on the repository detail page moves. The rule between sidebar sections was the connection section's own bottom border, so it drew even when no block followed. It is now a top border on the stats block, using Tailwind first: variants, so whichever block leads the sidebar carries no rule. A hosted repository renders no connection section and no longer opens with a stray line.
No changelog entry is included. The whole surface sits behind the disabled artifact_registry_ui feature flag, and every new schema field is marked experiment.
This MR ships the backend and frontend changes for the same GraphQL field together. On GitLab.com the standard guidance is to deploy the backend before the frontend. No user can reach this page while the flag is disabled, so the deploy window carries no user impact. Flagging it explicitly so a reviewer can judge whether it needs a different rollout approach.
References
Feature issue: gitlab-org#21052
Feature flag rollout issue: #605113
The feature flag is artifact_registry_ui. It is default-disabled (default_enabled: false) and has type wip.
Screenshots or screen recordings
| Before | After |
|---|---|
Screenshots are pending. The page is reachable only when the artifact_registry_ui feature flag is enabled.
How to set up and validate locally
- Enable the feature flag in the Rails console:
Feature.enable(:artifact_registry_ui). - Go to the organization Artifact Registry repositories route. The path shape is
/o/ORGANIZATION_PATH/-/artifact_registry/REGISTRY_SLUG/repositories. - Open a repository to see its artifact list. Check a remote npm repository first. It is the case that previously failed with
Cannot return null for non-nullable field ArtifactRegistryNpmPackage.versionsCount. - Confirm a remote repository shows the Last downloaded column. That column reads the new
lastDownloadedAtfield.
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.
Already verified locally:
- Jest: 52 suites, 1581 tests passing for the artifact registry frontend.
- RSpec: the value object, GraphQL type, request, fixture, and feature specs for this surface pass.
rake gitlab:graphql:validatereports both changed documents as OK.- RuboCop, ESLint, and Prettier are clean.
- No database migration and no new query against a large table, so no database review is needed.
- The new field reads an in-memory attribute off a value object that a single Artifact Registry HTTP call already returned, so it adds no N+1 risk. The existing request specs already assert exactly one outbound list request with no per-row follow-up.