Artifact registry: Add Edit and Copy URL to the detail header
What does this MR do and why?
Finishes the repository detail header for monolith/S05: it adds the Edit
button and the Copy repository URL kebab item, plus the whole copy-URL seam
behind that item.
This change is behind the feature flag :artifact_registry_ui (dark,
default_enabled: false).
The header region landed with its actions area holding the kebab alone, because
the monolith/S07 edit route did not exist at the time and the delete flow only
contributed its own item. Both write flows are merged now, so the two
merge-order conditionals in the S05 plan resolve and the header can mount what
the design shows.
Copy repository URL selects no repository field at all. The URL a user points
docker, mvn, or npm at is composed client-side, because Artifact Registry
returns no URL on the repository resource — so this MR also lands the seam that
composition needs, which is the bulk of the diff.
Changes
Editbutton in the header actions, ahead of the kebab, routing to the merged S07 edit route (REPOSITORY_EDIT_ROUTE_NAME).Copy repository URLas the first kebab item, aboveDelete repository. The destructive item is marked out by its variant alone — the design groups every item in one list with no divider.- The copy-URL seam:
Organizations::ArtifactRegistryHelperaddsclient_base_urlto the repositories mount data, derived as the origin of the already-configuredGitlab.config.artifact_registry.api_urlviaGitlab::UrlHelpers.normalized_base_url. No new setting and nogitlab.yml.examplechange — per ADR-009 the management and client APIs share a domain and differ only by the management API's/api/prefix.clientBaseUrljoins the SPAprovideblock.REPOSITORY_FORMAT_PATH_SEGMENTSinconstants.jsandbuildRepositoryClientUrlinutils.js.
- Copy goes through
copyToClipboardfrom~/lib/utils/copy_to_clipboard(navigator.clipboardis banned byeslint.config.mjs), reports through a toast, and sends a failed write to Sentry. - The edit form's
Cancelnow returns to the repository being edited, not to the repositories list. An edit is reached from its repository now that the header carries the Edit button. A create has no repository to return to, so the destination is per-mode:repository_form.vuetakes acancelRouteprop alongside the submit label and field set it already takes that way, defaulting to the list. - Tests: a new helper spec (the helper had none), the repositories controller request spec updated for the new mount key, and Jest coverage for the builder, the kebab item, the Edit button, and both cancel destinations.
The URL being copied
{origin}/{slug}/{format-segment}/{name}, with the container family collapsing
to one segment because a single set of OCI Distribution Spec endpoints serves
repositories of both docker and oci:
format |
segment | example |
|---|---|---|
MAVEN |
maven |
https://artifact-registry.example.com/acme/maven/my-repo |
NPM |
npm |
https://artifact-registry.example.com/acme/npm/my-repo |
DOCKER |
container |
https://artifact-registry.example.com/acme/container/my-repo |
OCI |
container |
https://artifact-registry.example.com/acme/container/my-repo |
An instance that configures no Artifact Registry composes no URL, so the item is left out rather than offering one that would not resolve.
Screenshots or screen recordings
| Before | After |
|---|---|
![]() |
![]() |
The design being matched, for reference — the
prototype
at the same viewport. Manage retention (monolith/S08), Manage access
(monolith/S09), and View setup instructions (a later monolith/S05 step) stay
out of scope; this MR lands the first item and the divider above the last.
How to set up and validate locally
- Enable the flag:
Feature.enable(:artifact_registry_ui)inrails c. - Visit
/o/<organization>/-/artifact_registry/acme/repositories—acmeisOrganizations::ArtifactRegistry::STUB_SLUG, and the controller renders 404 for any other slug. - The local Apollo resolvers seed an empty store, so create a repository first
through New repository → Hosted repository. Pick Docker to exercise
the shared
containersegment. - Back on the list, click the repository name. Note this has to be an in-SPA click — the mock store is in-memory, so a full page load empties it.
- Confirm the header renders
Editand the kebab, and thatEditnavigates to.../<name>/editwith the form prefilled. - Open the kebab and choose Copy repository URL. Paste it: on a GDK the
origin is
http://localhost:8080, so a Docker repositorymy-repogiveshttp://localhost:8080/acme/container/my-repo. - On the edit view, Cancel returns to the repository detail view. Cancel on the create view still returns to the list.
Verification performed
Copy repository URL composes from the configured Artifact Registry origin, so
verifying it locally means setting api_url in config/gitlab.yml (the key
ships commented out in gitlab.yml.example) and restarting Rails. Without it
the helper emits no clientBaseUrl and the kebab item is left out by design:
artifact_registry:
api_url: https://artifact-registry.example.comyarn jest ee/spec/frontend/packages_and_registries/artifact_registry— 19 suites, 295 examples, green.bin/rspec ee/spec/helpers/organizations/artifact_registry_helper_spec.rb(12 examples) andee/spec/requests/organizations/artifact_registry_repositories_controller_spec.rb(13 examples) — green.- ESLint, Prettier, and RuboCop clean on the touched files.
- Driven in a browser against a GDK: the composed URL, the toast (
aria-livepolite), the Edit navigation, and zero console errors.
Notes for review
- The
client_base_urlderivation.api_urlhas no production default andnormalized_base_urlreturns something like://for a partial value, so the helper emitsnilunless the result is a well-formed http(s) origin. It also readsGitlab.config.artifact_registry['api_url']through[]rather than.api_url, because a missing key raises on the reader and this renders on every repositories page. - Hiding vs. disabling the Copy item when no origin is configured is my call, not something the design fixes. Say the word if you would rather it render disabled.
Save changesstill returns to the repositories list, so cancelling an edit now lands somewhere different from saving one. The feedback asked about cancel specifically, so I have not touched save — but it is a one-line change inrepositories_edit_form.vueif you want the two to agree.- The
monolith/S04list plan's copy-URL step plans the same seam. It has not merged, so this MR lands it and those entries becomeModify.
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.


