Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/admin/users/components')
-rw-r--r--app/assets/javascripts/admin/users/components/actions/delete.vue4
-rw-r--r--app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue48
-rw-r--r--app/assets/javascripts/admin/users/components/associations/associations_list.vue65
-rw-r--r--app/assets/javascripts/admin/users/components/associations/associations_list_item.vue27
-rw-r--r--app/assets/javascripts/admin/users/components/modals/delete_user_modal.vue17
-rw-r--r--app/assets/javascripts/admin/users/components/user_actions.vue1
6 files changed, 151 insertions, 11 deletions
diff --git a/app/assets/javascripts/admin/users/components/actions/delete.vue b/app/assets/javascripts/admin/users/components/actions/delete.vue
index ae0c6731271..d4f9ff4e529 100644
--- a/app/assets/javascripts/admin/users/components/actions/delete.vue
+++ b/app/assets/javascripts/admin/users/components/actions/delete.vue
@@ -12,6 +12,10 @@ export default {
type: String,
required: true,
},
+ userId: {
+ type: Number,
+ required: true,
+ },
paths: {
type: Object,
required: true,
diff --git a/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue b/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue
index a39df1cbfb6..413804c9a3b 100644
--- a/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue
+++ b/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue
@@ -1,17 +1,26 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
-import { s__ } from '~/locale';
+import { GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import { associationsCount } from '~/api/user_api';
import eventHub, { EVENT_OPEN_DELETE_USER_MODAL } from '../modals/delete_user_modal_event_hub';
export default {
+ i18n: {
+ loading: __('Loading'),
+ },
components: {
GlDropdownItem,
+ GlLoadingIcon,
},
props: {
username: {
type: String,
required: true,
},
+ userId: {
+ type: Number,
+ required: true,
+ },
paths: {
type: Object,
required: true,
@@ -22,21 +31,38 @@ export default {
default: () => [],
},
},
+ data() {
+ return {
+ loading: false,
+ };
+ },
methods: {
- onClick() {
+ async onClick() {
+ this.loading = true;
+ try {
+ const { data: associationsCountData } = await associationsCount(this.userId);
+ this.openModal(associationsCountData);
+ } catch (error) {
+ this.openModal(new Error());
+ } finally {
+ this.loading = false;
+ }
+ },
+ openModal(associationsCountData) {
const { username, paths, userDeletionObstacles } = this;
eventHub.$emit(EVENT_OPEN_DELETE_USER_MODAL, {
username,
blockPath: paths.block,
deletePath: paths.deleteWithContributions,
userDeletionObstacles,
+ associationsCount: associationsCountData,
i18n: {
title: s__('AdminUsers|Delete User %{username} and contributions?'),
primaryButtonLabel: s__('AdminUsers|Delete user and contributions'),
- messageBody: s__(`AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues,
- merge requests, and groups linked to them. To avoid data loss,
- consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd},
- it cannot be undone or recovered.`),
+ messageBody: s__(`AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues,
+ merge requests, groups, and projects linked to them. To avoid data loss,
+ consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd},
+ you cannot undo this action or recover the data.`),
},
});
},
@@ -45,8 +71,12 @@ export default {
</script>
<template>
- <gl-dropdown-item @click="onClick">
- <span class="gl-text-red-500">
+ <gl-dropdown-item :disabled="loading" :aria-busy="loading" @click.capture.native.stop="onClick">
+ <div v-if="loading" class="gl-display-flex gl-align-items-center">
+ <gl-loading-icon class="gl-mr-3" />
+ {{ $options.i18n.loading }}
+ </div>
+ <span v-else class="gl-text-red-500">
<slot></slot>
</span>
</gl-dropdown-item>
diff --git a/app/assets/javascripts/admin/users/components/associations/associations_list.vue b/app/assets/javascripts/admin/users/components/associations/associations_list.vue
new file mode 100644
index 00000000000..12f98a02809
--- /dev/null
+++ b/app/assets/javascripts/admin/users/components/associations/associations_list.vue
@@ -0,0 +1,65 @@
+<script>
+import { GlAlert } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import AssociationsListItem from './associations_list_item.vue';
+
+export default {
+ i18n: {
+ errorMessage: s__(
+ "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted.",
+ ),
+ },
+ components: {
+ AssociationsListItem,
+ GlAlert,
+ },
+ props: {
+ associationsCount: {
+ type: [Object, Error],
+ required: true,
+ },
+ },
+ computed: {
+ hasError() {
+ return this.associationsCount instanceof Error;
+ },
+ hasAssociations() {
+ return Object.values(this.associationsCount).some((count) => count > 0);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-alert v-if="hasError" class="gl-mb-5" variant="danger" :dismissible="false">{{
+ $options.i18n.errorMessage
+ }}</gl-alert>
+ <ul v-else-if="hasAssociations" class="gl-mb-5">
+ <associations-list-item
+ v-if="associationsCount.groups_count"
+ :message="n__('%{count} group', '%{count} groups', associationsCount.groups_count)"
+ :count="associationsCount.groups_count"
+ />
+ <associations-list-item
+ v-if="associationsCount.projects_count"
+ :message="n__('%{count} project', '%{count} projects', associationsCount.projects_count)"
+ :count="associationsCount.projects_count"
+ />
+ <associations-list-item
+ v-if="associationsCount.issues_count"
+ :message="n__('%{count} issue', '%{count} issues', associationsCount.issues_count)"
+ :count="associationsCount.issues_count"
+ />
+ <associations-list-item
+ v-if="associationsCount.merge_requests_count"
+ :message="
+ n__(
+ '%{count} merge request',
+ '%{count} merge requests',
+ associationsCount.merge_requests_count,
+ )
+ "
+ :count="associationsCount.merge_requests_count"
+ />
+ </ul>
+</template>
diff --git a/app/assets/javascripts/admin/users/components/associations/associations_list_item.vue b/app/assets/javascripts/admin/users/components/associations/associations_list_item.vue
new file mode 100644
index 00000000000..88cb24aaf8f
--- /dev/null
+++ b/app/assets/javascripts/admin/users/components/associations/associations_list_item.vue
@@ -0,0 +1,27 @@
+<script>
+import { GlSprintf } from '@gitlab/ui';
+
+export default {
+ components: { GlSprintf },
+ props: {
+ message: {
+ type: String,
+ required: true,
+ },
+ count: {
+ type: Number,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <li>
+ <gl-sprintf :message="message">
+ <template #count>
+ <strong>{{ count }}</strong>
+ </template>
+ </gl-sprintf>
+ </li>
+</template>
diff --git a/app/assets/javascripts/admin/users/components/modals/delete_user_modal.vue b/app/assets/javascripts/admin/users/components/modals/delete_user_modal.vue
index 31fe86775ee..7f02d6dd5b1 100644
--- a/app/assets/javascripts/admin/users/components/modals/delete_user_modal.vue
+++ b/app/assets/javascripts/admin/users/components/modals/delete_user_modal.vue
@@ -2,6 +2,7 @@
import { GlModal, GlButton, GlFormInput, GlSprintf } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import UserDeletionObstaclesList from '~/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list.vue';
+import AssociationsList from '../associations/associations_list.vue';
import eventHub, { EVENT_OPEN_DELETE_USER_MODAL } from './delete_user_modal_event_hub';
export default {
@@ -11,6 +12,7 @@ export default {
GlFormInput,
GlSprintf,
UserDeletionObstaclesList,
+ AssociationsList,
},
props: {
csrfToken: {
@@ -25,6 +27,7 @@ export default {
blockPath: '',
deletePath: '',
userDeletionObstacles: [],
+ associationsCount: {},
i18n: {
title: '',
primaryButtonLabel: '',
@@ -53,11 +56,19 @@ export default {
eventHub.$off(EVENT_OPEN_DELETE_USER_MODAL, this.onOpenEvent);
},
methods: {
- onOpenEvent({ username, blockPath, deletePath, userDeletionObstacles, i18n }) {
+ onOpenEvent({
+ username,
+ blockPath,
+ deletePath,
+ userDeletionObstacles,
+ associationsCount = {},
+ i18n,
+ }) {
this.username = username;
this.blockPath = blockPath;
this.deletePath = deletePath;
this.userDeletionObstacles = userDeletionObstacles;
+ this.associationsCount = associationsCount;
this.i18n = i18n;
this.openModal();
},
@@ -100,8 +111,10 @@ export default {
:user-name="trimmedUsername"
/>
+ <associations-list :associations-count="associationsCount" />
+
<p>
- <gl-sprintf :message="s__('AdminUsers|To confirm, type %{username}')">
+ <gl-sprintf :message="s__('AdminUsers|To confirm, type %{username}.')">
<template #username>
<code data-testid="confirm-username" class="gl-white-space-pre-wrap">{{
trimmedUsername
diff --git a/app/assets/javascripts/admin/users/components/user_actions.vue b/app/assets/javascripts/admin/users/components/user_actions.vue
index 691a292673c..c1fb80959cf 100644
--- a/app/assets/javascripts/admin/users/components/user_actions.vue
+++ b/app/assets/javascripts/admin/users/components/user_actions.vue
@@ -139,6 +139,7 @@ export default {
:key="action"
:paths="userPaths"
:username="user.name"
+ :user-id="user.id"
:user-deletion-obstacles="obstaclesForUserDeletion"
:data-testid="`delete-${action}`"
>