debian-mirror-gitlab/app/assets/javascripts/members/components/table/members_table.vue

323 lines
10 KiB
Vue
Raw Normal View History

2021-01-03 14:25:43 +05:30
<script>
2021-06-08 01:23:25 +05:30
import { GlTable, GlBadge, GlPagination } from '@gitlab/ui';
2021-03-11 19:13:27 +05:30
import { mapState } from 'vuex';
2021-02-22 17:27:13 +05:30
import MembersTableCell from 'ee_else_ce/members/components/table/members_table_cell.vue';
import { canOverride, canRemove, canResend, canUpdate } from 'ee_else_ce/members/utils';
2021-06-08 01:23:25 +05:30
import { mergeUrlParams } from '~/lib/utils/url_utility';
2021-01-03 14:25:43 +05:30
import initUserPopovers from '~/user_popovers';
2021-11-18 22:05:49 +05:30
import {
2022-03-02 08:16:31 +05:30
FIELD_KEY_ACTIONS,
2021-11-18 22:05:49 +05:30
FIELDS,
ACTIVE_TAB_QUERY_PARAM_NAME,
2022-01-26 12:08:38 +05:30
TAB_QUERY_PARAM_VALUES,
2021-11-18 22:05:49 +05:30
MEMBER_STATE_AWAITING,
2022-04-04 11:22:00 +05:30
MEMBER_STATE_ACTIVE,
2021-11-18 22:05:49 +05:30
USER_STATE_BLOCKED_PENDING_APPROVAL,
2022-04-04 11:22:00 +05:30
BADGE_LABELS_AWAITING_USER_SIGNUP,
2021-11-18 22:05:49 +05:30
BADGE_LABELS_PENDING_OWNER_APPROVAL,
} from '../../constants';
2021-03-11 19:13:27 +05:30
import RemoveGroupLinkModal from '../modals/remove_group_link_modal.vue';
2021-10-27 15:23:28 +05:30
import RemoveMemberModal from '../modals/remove_member_modal.vue';
2021-01-03 14:25:43 +05:30
import CreatedAt from './created_at.vue';
2021-03-11 19:13:27 +05:30
import ExpirationDatepicker from './expiration_datepicker.vue';
2021-01-03 14:25:43 +05:30
import MemberActionButtons from './member_action_buttons.vue';
2021-03-11 19:13:27 +05:30
import MemberAvatar from './member_avatar.vue';
import MemberSource from './member_source.vue';
2021-01-03 14:25:43 +05:30
import RoleDropdown from './role_dropdown.vue';
export default {
name: 'MembersTable',
components: {
GlTable,
GlBadge,
2021-06-08 01:23:25 +05:30
GlPagination,
2021-01-03 14:25:43 +05:30
MemberAvatar,
CreatedAt,
MembersTableCell,
MemberSource,
MemberActionButtons,
RoleDropdown,
RemoveGroupLinkModal,
2021-10-27 15:23:28 +05:30
RemoveMemberModal,
2021-01-29 00:20:46 +05:30
ExpirationDatepicker,
LdapOverrideConfirmationModal: () =>
2021-02-22 17:27:13 +05:30
import('ee_component/members/components/ldap/ldap_override_confirmation_modal.vue'),
2021-01-03 14:25:43 +05:30
},
2021-04-29 21:17:54 +05:30
inject: ['namespace', 'currentUserId'],
2021-09-30 23:02:18 +05:30
props: {
tabQueryParamValue: {
type: String,
required: false,
default: '',
},
},
2021-01-03 14:25:43 +05:30
computed: {
2021-04-29 21:17:54 +05:30
...mapState({
members(state) {
return state[this.namespace].members;
},
tableFields(state) {
return state[this.namespace].tableFields;
},
tableAttrs(state) {
return state[this.namespace].tableAttrs;
},
2021-06-08 01:23:25 +05:30
pagination(state) {
return state[this.namespace].pagination;
},
2021-04-29 21:17:54 +05:30
}),
2022-03-02 08:16:31 +05:30
filteredAndModifiedFields() {
2021-03-08 18:12:59 +05:30
return FIELDS.filter(
(field) => this.tableFields.includes(field.key) && this.showField(field),
2022-03-02 08:16:31 +05:30
).map(this.modifyFieldDefinition);
2021-01-29 00:20:46 +05:30
},
userIsLoggedIn() {
return this.currentUserId !== null;
2021-01-03 14:25:43 +05:30
},
2021-06-08 01:23:25 +05:30
showPagination() {
const { paramName, currentPage, perPage, totalItems } = this.pagination;
return paramName && currentPage && perPage && totalItems;
},
2022-01-26 12:08:38 +05:30
isInvitedUser() {
return this.tabQueryParamValue === TAB_QUERY_PARAM_VALUES.invite;
},
2021-01-03 14:25:43 +05:30
},
mounted() {
initUserPopovers(this.$el.querySelectorAll('.js-user-link'));
},
2021-01-29 00:20:46 +05:30
methods: {
2021-03-08 18:12:59 +05:30
hasActionButtons(member) {
return (
2021-03-11 19:13:27 +05:30
canRemove(member) ||
2021-03-08 18:12:59 +05:30
canResend(member) ||
2021-03-11 19:13:27 +05:30
canUpdate(member, this.currentUserId) ||
2021-03-08 18:12:59 +05:30
canOverride(member)
);
},
2021-01-29 00:20:46 +05:30
showField(field) {
2022-03-02 08:16:31 +05:30
switch (field.key) {
case FIELD_KEY_ACTIONS:
if (!this.userIsLoggedIn) {
return false;
}
2021-01-29 00:20:46 +05:30
2022-03-02 08:16:31 +05:30
return this.members.some((member) => this.hasActionButtons(member));
default:
return true;
}
2021-01-29 00:20:46 +05:30
},
2022-03-02 08:16:31 +05:30
modifyFieldDefinition(field) {
switch (field.key) {
case FIELD_KEY_ACTIONS:
return {
...field,
tdClass: this.actionsFieldTdClass,
};
default:
return field;
2021-01-29 00:20:46 +05:30
}
2021-03-08 18:12:59 +05:30
},
2022-03-02 08:16:31 +05:30
actionsFieldTdClass(value, key, member) {
2021-03-08 18:12:59 +05:30
if (this.hasActionButtons(member)) {
return 'col-actions';
}
2021-03-11 19:13:27 +05:30
return ['col-actions', 'gl-display-none!', 'gl-lg-display-table-cell!'];
2021-03-08 18:12:59 +05:30
},
tbodyTrAttr(member) {
return {
...this.tableAttrs.tr,
...(member?.id && { 'data-testid': `members-table-row-${member.id}` }),
};
2021-01-29 00:20:46 +05:30
},
2021-06-08 01:23:25 +05:30
paginationLinkGenerator(page) {
const { params = {}, paramName } = this.pagination;
2021-09-30 23:02:18 +05:30
return mergeUrlParams(
{
...params,
[ACTIVE_TAB_QUERY_PARAM_NAME]:
this.tabQueryParamValue !== '' ? this.tabQueryParamValue : null,
[paramName]: page,
},
window.location.href,
);
2021-06-08 01:23:25 +05:30
},
2021-11-18 22:05:49 +05:30
/**
* Returns whether it's a new or existing user
*
* If memberInviteMetadata doesn't exist, it means we're adding an existing user
* to the Group/Project, so `isNewUser` should be false.
* If memberInviteMetadata exists but `userState` has content,
* the user has registered but is awaiting root approval
*
* @param {object} memberInviteMetadata - MemberEntity.invite
* @see {@link ~/app/serializers/member_entity.rb}
* @returns {boolean}
*/
2022-04-04 11:22:00 +05:30
isNewUser(memberInviteMetadata, memberState) {
return (
memberInviteMetadata &&
!memberInviteMetadata.userState &&
memberState !== MEMBER_STATE_ACTIVE
);
2021-11-18 22:05:49 +05:30
},
/**
* Returns whether the user is awaiting root approval
*
* This checks User.state exposed via MemberEntity
*
* @param {object} memberInviteMetadata - MemberEntity.invite
* @see {@link ~/app/serializers/member_entity.rb}
* @returns {boolean}
*/
isUserPendingRootApproval(memberInviteMetadata) {
return memberInviteMetadata?.userState === USER_STATE_BLOCKED_PENDING_APPROVAL;
},
/**
* Returns whether the member is awaiting owner approval
*
* This checks Member.state exposed via MemberEntity
*
* @param {Number} memberState - Member.state exposed via MemberEntity.state
* @see {@link ~/ee/app/models/ee/member.rb}
* @see {@link ~/app/serializers/member_entity.rb}
* @returns {boolean}
*/
isMemberPendingOwnerApproval(memberState) {
return memberState === MEMBER_STATE_AWAITING;
},
isUserAwaiting(memberInviteMetadata, memberState) {
return (
this.isUserPendingRootApproval(memberInviteMetadata) ||
this.isMemberPendingOwnerApproval(memberState)
);
},
shouldAddPendingOwnerApprovalBadge(memberInviteMetadata, memberState) {
return (
this.isUserAwaiting(memberInviteMetadata, memberState) &&
!this.isNewUser(memberInviteMetadata)
);
},
/**
* Returns the string to be used in the invite badge
*
* @param {object} memberInviteMetadata - MemberEntity.invite
* @see {@link ~/app/serializers/member_entity.rb}
* @param {Number} memberState - Member.state exposed via MemberEntity.state
* @see {@link ~/ee/app/models/ee/member.rb}
* @returns {string}
*/
inviteBadge(memberInviteMetadata, memberState) {
2022-04-04 11:22:00 +05:30
if (this.isNewUser(memberInviteMetadata, memberState)) {
return BADGE_LABELS_AWAITING_USER_SIGNUP;
}
2021-11-18 22:05:49 +05:30
if (this.shouldAddPendingOwnerApprovalBadge(memberInviteMetadata, memberState)) {
return BADGE_LABELS_PENDING_OWNER_APPROVAL;
}
return '';
},
2021-01-29 00:20:46 +05:30
},
2021-01-03 14:25:43 +05:30
};
</script>
<template>
<div>
<gl-table
2021-01-29 00:20:46 +05:30
v-bind="tableAttrs.table"
2021-01-03 14:25:43 +05:30
class="members-table"
2021-01-29 00:20:46 +05:30
data-testid="members-table"
2021-01-03 14:25:43 +05:30
head-variant="white"
stacked="lg"
2022-03-02 08:16:31 +05:30
:fields="filteredAndModifiedFields"
2021-01-03 14:25:43 +05:30
:items="members"
primary-key="id"
thead-class="border-bottom"
:empty-text="__('No members found')"
show-empty
2021-03-08 18:12:59 +05:30
:tbody-tr-attr="tbodyTrAttr"
2021-01-03 14:25:43 +05:30
>
2021-06-08 01:23:25 +05:30
<template #head()="{ label }">
{{ label }}
</template>
2021-01-03 14:25:43 +05:30
<template #cell(account)="{ item: member }">
<members-table-cell #default="{ memberType, isCurrentUser }" :member="member">
<member-avatar
:member-type="memberType"
:is-current-user="isCurrentUser"
:member="member"
/>
</members-table-cell>
</template>
<template #cell(source)="{ item: member }">
<members-table-cell #default="{ isDirectMember }" :member="member">
<member-source :is-direct-member="isDirectMember" :member-source="member.source" />
</members-table-cell>
</template>
<template #cell(granted)="{ item: { createdAt, createdBy } }">
<created-at :date="createdAt" :created-by="createdBy" />
</template>
2021-11-18 22:05:49 +05:30
<template #cell(invited)="{ item: { createdAt, createdBy, invite, state } }">
2021-01-03 14:25:43 +05:30
<created-at :date="createdAt" :created-by="createdBy" />
2021-11-18 22:05:49 +05:30
<gl-badge v-if="inviteBadge(invite, state)" data-testid="invited-badge">{{
inviteBadge(invite, state)
}}</gl-badge>
2021-01-03 14:25:43 +05:30
</template>
<template #cell(requested)="{ item: { createdAt } }">
<created-at :date="createdAt" />
</template>
<template #cell(maxRole)="{ item: member }">
<members-table-cell #default="{ permissions }" :member="member">
2021-01-29 00:20:46 +05:30
<role-dropdown v-if="permissions.canUpdate" :permissions="permissions" :member="member" />
2021-01-03 14:25:43 +05:30
<gl-badge v-else>{{ member.accessLevel.stringValue }}</gl-badge>
</members-table-cell>
</template>
2021-01-29 00:20:46 +05:30
<template #cell(expiration)="{ item: member }">
<members-table-cell #default="{ permissions }" :member="member">
<expiration-datepicker :permissions="permissions" :member="member" />
</members-table-cell>
</template>
2021-01-03 14:25:43 +05:30
<template #cell(actions)="{ item: member }">
<members-table-cell #default="{ memberType, isCurrentUser, permissions }" :member="member">
<member-action-buttons
:member-type="memberType"
:is-current-user="isCurrentUser"
2022-01-26 12:08:38 +05:30
:is-invited-user="isInvitedUser"
2021-01-03 14:25:43 +05:30
:permissions="permissions"
:member="member"
/>
</members-table-cell>
</template>
<template #head(actions)="{ label }">
<span data-testid="col-actions" class="gl-sr-only">{{ label }}</span>
</template>
</gl-table>
2021-06-08 01:23:25 +05:30
<gl-pagination
v-if="showPagination"
:value="pagination.currentPage"
:per-page="pagination.perPage"
:total-items="pagination.totalItems"
:link-gen="paginationLinkGenerator"
:prev-text="__('Prev')"
:next-text="__('Next')"
:label-next-page="__('Go to next page')"
:label-prev-page="__('Go to previous page')"
align="center"
/>
2021-01-03 14:25:43 +05:30
<remove-group-link-modal />
2021-10-27 15:23:28 +05:30
<remove-member-modal />
2021-01-29 00:20:46 +05:30
<ldap-override-confirmation-modal />
2021-01-03 14:25:43 +05:30
</div>
</template>