Artifact Registry: Add the repository delete flow

What does this MR do and why?

This change is behind the feature flag :artifact_registry_ui (default off).

Delete is the last repository write affordance monolith/S07 owns, and the one CRUD verb still missing. Per the spec it has no route — it is a type-to-confirm modal over the current view, idempotent, evicting the cached list and toasting on success. This is S07 Step 8.

The design proposal puts delete in an actions kebab on the repository detail header — not on the list rows. That kebab holds five items; only Delete repository is in scope here. Its other four are out (see below), which is the kebab !248319 (merged) defers to "a separate change".

Stacked on !248319 (merged) — it creates repository_header.vue, the only place the kebab can mount. Review that one first; this MR's diff is only the commit on top.

Changes

  • repositories/detail/repository_actions.vue (new) — the kebab. One variant="danger" item, Delete repository. The toggle is icon-only, so its accessible name names the repository (More actions for %{name}) rather than saying only "More actions".
  • repositories/components/delete_repository_modal.vue (new) — the type-to-confirm modal plus the delete mutation, eviction, toast, and return to the list. Follows virtual_registries/components/registry/delete_modal.vue, which owns the same three things.
  • repositories/detail/repository_header.vue — mounts the actions in page_heading.vue's existing, unused actions slot. Four lines.
  • GraphQL — a @client delete mutation, its typedefs, and a mock resolver. The mock treats deleting an absent repository as success, matching the idempotent delete the service offers (criterion 3) and deliberately unlike a read, which resolves null on a miss.
  • graphql/utils/cache_update.jsevictDeletedRepository drops the connection field across every argument variant and the repository entity, so navigating back to a deleted repository cannot read it out of the cache as though it still existed. evictRepositoriesList and the create path are untouched.

One CE change, worth a frontend maintainer's eye

app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue gains a phraseLabel prop.

I reused that component rather than hand-rolling a modal because it already does everything this step's accessibility criteria ask for — a real <label for> on the input, autofocus on shown, phrase matching, and a focus trap. Container registry's own delete modal is the cautionary example: its input has no label at all.

The input label was the one piece of copy it did not let a caller set (CONFIRM_DANGER_PHRASE_TEXT was hardcoded), and the design specifies different wording. The prop defaults to that constant, so all four existing callers — transfer_group_form.vue, transfer_project_form.vue, settings_panel.vue, init_confirm_danger.js — are unchanged; I ran their specs. Happy to split this into its own ~5-line MR if you would rather review it separately.

Screenshots or screen recordings

Design Implementation
proto-delete-modal step8-modal-disabled

The actions kebab in the header, with its one in-scope item:

step8-kebab-open

The one deliberate difference from the design: the repository name renders inline after the instruction rather than on its own line, because the shared component interpolates it through GlSprintf. Copy matches; if @bonnie-tsang wants the line break, the follow-up is a slot inside that component's <label>.

How to set up and validate locally

  1. Enable the flag: Feature.enable(:artifact_registry_ui, Organizations::Organization.first).
  2. Visit /o/<org>/-/artifact_registry/acme/repositories (the slug is stubbed to acme) and create a repository — the mock seeds empty on each load.
  3. Click its name to open the detail page. The kebab sits in the header row beside the title.
  4. Open it, choose Delete repository, and check the modal against the design above. The confirm button starts disabled.
  5. Type a wrong name — still disabled. Type the repository name — enabled.
  6. Confirm. You should land on the list with a success toast and the row gone.
  7. Keyboard: Enter on the kebab, to the item, Enter to open. Focus lands in the input; Esc closes.

Agent Notes

Two deviations from the merged S07 plan:

  1. Plan Step 8 puts the delete button on the edit view. It predates both the detail page and its header, and the design puts delete in the detail kebab. Delete-from-edit is not built here — I did not want to assume it is wanted. @rchanila / @bonnie-tsang: should the edit page carry one too, or is the detail kebab the only entry point?
  2. The plan names the modal repositories/delete_repository_modal.vue (flat). The shipped tree uses subfolders, so it went to repositories/components/ beside repository_form.vue.

Verified in GDK, not just in Jest: created a repository, deleted it through the modal, and confirmed the list refetched empty with the toast. Also checked the wrong-name/right-name gating and that the input is autofocused and properly labelled (role="dialog", label[for="confirm_name_input"]).

Cache behaviour worth a look. Evicting the entity as well as the list field is the part I would most like a second opinion on. Without it, deleting api-gateway and then navigating to …/repositories/api-gateway reads the still-cached entity and renders a repository that no longer exists. The spec only asks for list eviction, so this is slightly beyond it.

On the modal auto-closing: the shared component watches confirmLoading and hides itself on the true→false transition, so this component never sets visible back to false by hand. That is non-obvious if you are reading only this diff.

Pre-existing, unrelated: spec/frontend/projects/settings/components/transfer_project_form_spec.js fails as a suite (0 tests failing) on the base branch with none of my changes applied. I checked by stashing. Not introduced here.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.


This MR was authored with the assistance of an AI coding agent and reviewed by @zcuddy before submission.

Merge request reports

Loading
Loading