Show a loading state while a project transfer runs
What does this MR do and why?
Clicking Confirm in the Transfer project modal closed the modal and left the page idle while the transfer ran. A transfer can take tens of seconds, so users reported it feeling stuck or broken and retried. confirm_danger_modal.vue already supports a confirmLoading prop (spinner plus disabled on the primary action); nothing threaded it through.
The fix:
confirm_danger.vue(shared wrapper) gains a pass-throughconfirmLoadingprop and forwards the modal's confirm event object to consumers.transfer_project_form.vueowns the transfer flow. It takestargetFormIdandtargetHiddenInputIdprops; a watcher writes the selected namespace id to the hidden input, andonConfirmprevents the modal's default close, flipsconfirmLoading, and callsform.submit()inside a try/catch that resetsconfirmLoadingif the submit throws. The modal stays open with the Confirm button in its loading state until the browser navigates to the transfer result.init_transfer_project_form.jsis mount-and-props only: it reads the target form and hidden input ids off the element's dataset and passes them to the component. No logic and no event handling live there.
Consumer audit for the shared wrapper (confirm_danger.vue):
| Consumer | Effect |
|---|---|
projects/settings/components/transfer_project_form.vue |
The fix; opts in. |
init_confirm_danger.js (project/group removal forms) |
Handler ignores the new event argument; confirmLoading defaults to false. Unchanged. |
groups/components/transfer_group_form.vue |
Re-emits confirm without arguments, as before. Unchanged (the same loading treatment could be threaded through for group transfers as a follow-up). |
pages/projects/shared/permissions/components/settings_panel.vue |
Re-emits confirm without arguments. Unchanged. |
No consumer imports confirm_danger_modal.vue directly, and the modal itself is untouched. With the beta groups_and_projects_async_transfer flag enabled, the submit returns quickly and the loading state just bridges the redirect.
References
Related to Transfer project button in modal is clickable while transfer is in progress (#344578).
Screenshots or screen recordings
Screen recordings
| Flag state | Recording |
|---|---|
| Off (synchronous transfer) | |
On (groups_and_projects_async_transfer) |
Flag off: Confirm stays in a loading state through the request, then the browser navigates to the transferred project. Flag on: a brief loading bridge, then redirect to the project settings page with an info alert that the transfer is scheduled. Both were captured on a local development instance, so the synchronous window shown is only a couple of seconds. On GitLab.com a transfer can take much longer, which is the window the loading state covers.
| View | Before | After |
|---|---|---|
| After clicking Confirm | ![]() |
![]() |
| Modal region (zoom) | ![]() |
![]() |
State after clicking Confirm with the transfer request in flight. Before: the modal closes and the page gives no sign a transfer is running (the Transfer project button is even enabled again). After: the modal stays open and Confirm shows a spinner, non-interactive (aria-disabled). The zoom row crops the same modal region on both sides; on the before it shows the page beneath because the modal has closed.
How to set up and validate locally
- In a project you own, go to Settings > General > Advanced > Transfer project.
- Pick a target namespace, click Transfer project, type the confirmation phrase, and click Confirm.
- The modal stays open and the Confirm button shows a spinner and is not clickable until the transfer result page loads.
- Enable the
groups_and_projects_async_transferfeature flag to see the other flow: after Confirm, a brief loading state precedes a redirect to the project settings page with a banner that the transfer is scheduled.
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.



