From 17deb2a503bb8163514fe37618bf36f75376b9ae Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 9 Jan 2023 18:10:06 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .../components/action_dropdowns/constants.js | 4 ++ .../action_dropdowns/leave_group_dropdown_item.vue | 6 ++- .../remove_member_dropdown_item.vue | 6 +++ .../action_dropdowns/user_action_dropdown.vue | 24 +++++++-- .../members/components/modals/leave_modal.vue | 63 ++++++++++++++++++---- .../components/modals/remove_member_modal.vue | 36 ++++++++----- .../members/components/table/members_table.vue | 12 ++++- .../components/table/members_table_cell.vue | 7 ++- app/assets/javascripts/members/utils.js | 3 ++ 9 files changed, 129 insertions(+), 32 deletions(-) (limited to 'app/assets/javascripts/members') diff --git a/app/assets/javascripts/members/components/action_dropdowns/constants.js b/app/assets/javascripts/members/components/action_dropdowns/constants.js index f6718713e2b..eb5b2182ece 100644 --- a/app/assets/javascripts/members/components/action_dropdowns/constants.js +++ b/app/assets/javascripts/members/components/action_dropdowns/constants.js @@ -11,4 +11,8 @@ export const I18N = { confirmOrphanedUserRemoval: s__( 'Members|Are you sure you want to remove this orphaned member from "%{group}"?', ), + personalProjectOwnerCannotBeRemoved: s__("Members|A personal project's owner cannot be removed."), + lastGroupOwnerCannotBeRemoved: s__( + 'Members|A group must have at least one owner. To remove the member, assign a new owner.', + ), }; diff --git a/app/assets/javascripts/members/components/action_dropdowns/leave_group_dropdown_item.vue b/app/assets/javascripts/members/components/action_dropdowns/leave_group_dropdown_item.vue index b5e0317d54f..15606ad567c 100644 --- a/app/assets/javascripts/members/components/action_dropdowns/leave_group_dropdown_item.vue +++ b/app/assets/javascripts/members/components/action_dropdowns/leave_group_dropdown_item.vue @@ -18,6 +18,10 @@ export default { type: Object, required: true, }, + permissions: { + type: Object, + required: true, + }, }, }; @@ -27,6 +31,6 @@ export default { - + diff --git a/app/assets/javascripts/members/components/action_dropdowns/remove_member_dropdown_item.vue b/app/assets/javascripts/members/components/action_dropdowns/remove_member_dropdown_item.vue index 18f1a8739bf..f224aaa31f7 100644 --- a/app/assets/javascripts/members/components/action_dropdowns/remove_member_dropdown_item.vue +++ b/app/assets/javascripts/members/components/action_dropdowns/remove_member_dropdown_item.vue @@ -40,6 +40,11 @@ export default { required: false, default: () => ({}), }, + preventRemoval: { + type: Boolean, + required: false, + default: false, + }, }, computed: { ...mapState({ @@ -55,6 +60,7 @@ export default { memberModelType: this.memberModelType, message: this.modalMessage, userDeletionObstacles: this.userDeletionObstacles, + preventRemoval: this.preventRemoval, }; }, }, diff --git a/app/assets/javascripts/members/components/action_dropdowns/user_action_dropdown.vue b/app/assets/javascripts/members/components/action_dropdowns/user_action_dropdown.vue index 4e5e6b0cab4..816481d4329 100644 --- a/app/assets/javascripts/members/components/action_dropdowns/user_action_dropdown.vue +++ b/app/assets/javascripts/members/components/action_dropdowns/user_action_dropdown.vue @@ -2,6 +2,10 @@ import { GlDropdown, GlTooltipDirective } from '@gitlab/ui'; import { sprintf } from '~/locale'; import { parseUserDeletionObstacles } from '~/vue_shared/components/user_deletion_obstacles/utils'; +import { + MEMBER_MODEL_TYPE_GROUP_MEMBER, + MEMBER_MODEL_TYPE_PROJECT_MEMBER, +} from '~/members/constants'; import { I18N } from './constants'; import LeaveGroupDropdownItem from './leave_group_dropdown_item.vue'; import RemoveMemberDropdownItem from './remove_member_dropdown_item.vue'; @@ -37,6 +41,16 @@ export default { modalMessage() { const { user, source } = this.member; + if (this.permissions.canRemoveBlockedByLastOwner) { + if (this.member.type === MEMBER_MODEL_TYPE_PROJECT_MEMBER) { + return I18N.personalProjectOwnerCannotBeRemoved; + } + + if (this.member.type === MEMBER_MODEL_TYPE_GROUP_MEMBER) { + return I18N.lastGroupOwnerCannotBeRemoved; + } + } + if (user) { return sprintf( this.$options.i18n.confirmNormalUserRemoval, @@ -54,7 +68,10 @@ export default { }; }, showDropdown() { - return this.permissions.canRemove || this.showLdapOverride; + return this.showLeaveOrRemove || this.showLdapOverride; + }, + showLeaveOrRemove() { + return this.permissions.canRemove || this.permissions.canRemoveBlockedByLastOwner; }, showLdapOverride() { return this.permissions.canOverride && !this.member.isOverridden; @@ -76,8 +93,8 @@ export default { data-testid="user-action-dropdown" data-qa-selector="user_action_dropdown" > - diff --git a/app/assets/javascripts/members/components/table/members_table.vue b/app/assets/javascripts/members/components/table/members_table.vue index c847f9c8311..6d242f38d0e 100644 --- a/app/assets/javascripts/members/components/table/members_table.vue +++ b/app/assets/javascripts/members/components/table/members_table.vue @@ -2,7 +2,14 @@ import { GlTable, GlBadge, GlPagination } from '@gitlab/ui'; import { mapState } from 'vuex'; import MembersTableCell from 'ee_else_ce/members/components/table/members_table_cell.vue'; -import { canUnban, canOverride, canRemove, canResend, canUpdate } from 'ee_else_ce/members/utils'; +import { + canUnban, + canOverride, + canRemove, + canRemoveBlockedByLastOwner, + canResend, + canUpdate, +} from 'ee_else_ce/members/utils'; import { mergeUrlParams } from '~/lib/utils/url_utility'; import { FIELD_KEY_ACTIONS, @@ -43,7 +50,7 @@ export default { LdapOverrideConfirmationModal: () => import('ee_component/members/components/ldap/ldap_override_confirmation_modal.vue'), }, - inject: ['namespace', 'currentUserId'], + inject: ['namespace', 'currentUserId', 'canManageMembers'], props: { tabQueryParamValue: { type: String, @@ -84,6 +91,7 @@ export default { hasActionButtons(member) { return ( canRemove(member) || + canRemoveBlockedByLastOwner(member, this.canManageMembers) || canResend(member) || canUpdate(member, this.currentUserId) || canOverride(member) || diff --git a/app/assets/javascripts/members/components/table/members_table_cell.vue b/app/assets/javascripts/members/components/table/members_table_cell.vue index 51eff428d63..407cbc55dd3 100644 --- a/app/assets/javascripts/members/components/table/members_table_cell.vue +++ b/app/assets/javascripts/members/components/table/members_table_cell.vue @@ -5,13 +5,14 @@ import { isDirectMember, isCurrentUser, canRemove, + canRemoveBlockedByLastOwner, canResend, canUpdate, } from '../../utils'; export default { name: 'MembersTableCell', - inject: ['currentUserId'], + inject: ['currentUserId', 'canManageMembers'], props: { member: { type: Object, @@ -45,6 +46,9 @@ export default { isCurrentUser() { return isCurrentUser(this.member, this.currentUserId); }, + canRemoveBlockedByLastOwner() { + return canRemoveBlockedByLastOwner(this.member, this.canManageMembers); + }, canRemove() { return canRemove(this.member); }, @@ -62,6 +66,7 @@ export default { isCurrentUser: this.isCurrentUser, permissions: { canRemove: this.canRemove, + canRemoveBlockedByLastOwner: this.canRemoveBlockedByLastOwner, canResend: this.canResend, canUpdate: this.canUpdate, }, diff --git a/app/assets/javascripts/members/utils.js b/app/assets/javascripts/members/utils.js index bf87ab53d36..b7af97ebac5 100644 --- a/app/assets/javascripts/members/utils.js +++ b/app/assets/javascripts/members/utils.js @@ -51,6 +51,9 @@ export const canRemove = (member) => { return isDirectMember(member) && member.canRemove; }; +export const canRemoveBlockedByLastOwner = (member, canManageMembers) => + isDirectMember(member) && canManageMembers && member.isLastOwner; + export const canResend = (member) => { return Boolean(member.invite?.canResend); }; -- cgit v1.2.3