diff options
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/members')
26 files changed, 0 insertions, 1488 deletions
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/access_request_action_buttons.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/access_request_action_buttons.vue deleted file mode 100644 index 10078d5cd64..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/action_buttons/access_request_action_buttons.vue +++ /dev/null @@ -1,59 +0,0 @@ -<script> -import ActionButtonGroup from './action_button_group.vue'; -import RemoveMemberButton from './remove_member_button.vue'; -import ApproveAccessRequestButton from './approve_access_request_button.vue'; -import { s__, sprintf } from '~/locale'; - -export default { - name: 'AccessRequestActionButtons', - components: { ActionButtonGroup, RemoveMemberButton, ApproveAccessRequestButton }, - props: { - member: { - type: Object, - required: true, - }, - permissions: { - type: Object, - required: true, - }, - isCurrentUser: { - type: Boolean, - required: true, - }, - }, - computed: { - message() { - const { user, source } = this.member; - - if (this.isCurrentUser) { - return sprintf( - s__('Members|Are you sure you want to withdraw your access request for "%{source}"'), - { source: source.name }, - ); - } - - return sprintf( - s__('Members|Are you sure you want to deny %{usersName}\'s request to join "%{source}"'), - { usersName: user.name, source: source.name }, - ); - }, - }, -}; -</script> - -<template> - <action-button-group> - <div v-if="permissions.canUpdate" class="gl-px-1"> - <approve-access-request-button :member-id="member.id" /> - </div> - <div v-if="permissions.canRemove" class="gl-px-1"> - <remove-member-button - :member-id="member.id" - :message="message" - :title="s__('Member|Deny access')" - :is-access-request="true" - icon="close" - /> - </div> - </action-button-group> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/action_button_group.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/action_button_group.vue deleted file mode 100644 index 8356fdb60b1..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/action_buttons/action_button_group.vue +++ /dev/null @@ -1,11 +0,0 @@ -<script> -export default { - name: 'ActionButtonGroup', -}; -</script> - -<template> - <div class="gl-display-flex gl-flex-align-items-center gl-justify-content-end gl-mx-n1"> - <slot></slot> - </div> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/approve_access_request_button.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/approve_access_request_button.vue deleted file mode 100644 index e8a53ff173d..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/action_buttons/approve_access_request_button.vue +++ /dev/null @@ -1,42 +0,0 @@ -<script> -import { mapState } from 'vuex'; -import { GlButton, GlForm, GlTooltipDirective } from '@gitlab/ui'; -import csrf from '~/lib/utils/csrf'; -import { __ } from '~/locale'; - -export default { - name: 'ApproveAccessRequestButton', - csrf, - title: __('Grant access'), - components: { GlButton, GlForm }, - directives: { - GlTooltip: GlTooltipDirective, - }, - props: { - memberId: { - type: Number, - required: true, - }, - }, - computed: { - ...mapState(['memberPath']), - approvePath() { - return this.memberPath.replace(/:id$/, `${this.memberId}/approve_access_request`); - }, - }, -}; -</script> - -<template> - <gl-form :action="approvePath" method="post"> - <input :value="$options.csrf.token" type="hidden" name="authenticity_token" /> - <gl-button - v-gl-tooltip.hover - :title="$options.title" - :aria-label="$options.title" - icon="check" - variant="success" - type="submit" - /> - </gl-form> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/group_action_buttons.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/group_action_buttons.vue deleted file mode 100644 index 2aebfe80db5..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/action_buttons/group_action_buttons.vue +++ /dev/null @@ -1,27 +0,0 @@ -<script> -import ActionButtonGroup from './action_button_group.vue'; -import RemoveGroupLinkButton from './remove_group_link_button.vue'; - -export default { - name: 'GroupActionButtons', - components: { ActionButtonGroup, RemoveGroupLinkButton }, - props: { - member: { - type: Object, - required: true, - }, - permissions: { - type: Object, - required: true, - }, - }, -}; -</script> - -<template> - <action-button-group> - <div v-if="permissions.canRemove" class="gl-px-1"> - <remove-group-link-button :group-link="member" /> - </div> - </action-button-group> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/invite_action_buttons.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/invite_action_buttons.vue deleted file mode 100644 index 2b0a75640e2..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/action_buttons/invite_action_buttons.vue +++ /dev/null @@ -1,48 +0,0 @@ -<script> -import ActionButtonGroup from './action_button_group.vue'; -import RemoveMemberButton from './remove_member_button.vue'; -import ResendInviteButton from './resend_invite_button.vue'; -import { s__, sprintf } from '~/locale'; - -export default { - name: 'InviteActionButtons', - components: { ActionButtonGroup, RemoveMemberButton, ResendInviteButton }, - props: { - member: { - type: Object, - required: true, - }, - permissions: { - type: Object, - required: true, - }, - }, - computed: { - message() { - const { invite, source } = this.member; - - return sprintf( - s__( - 'Members|Are you sure you want to revoke the invitation for %{inviteEmail} to join "%{source}"', - ), - { inviteEmail: invite.email, source: source.name }, - ); - }, - }, -}; -</script> - -<template> - <action-button-group> - <div v-if="permissions.canResend" class="gl-px-1"> - <resend-invite-button :member-id="member.id" /> - </div> - <div v-if="permissions.canRemove" class="gl-px-1"> - <remove-member-button - :member-id="member.id" - :message="message" - :title="s__('Member|Revoke invite')" - /> - </div> - </action-button-group> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/leave_button.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/leave_button.vue deleted file mode 100644 index d9976e7181c..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/action_buttons/leave_button.vue +++ /dev/null @@ -1,40 +0,0 @@ -<script> -import { GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui'; -import { __ } from '~/locale'; -import LeaveModal from '../modals/leave_modal.vue'; -import { LEAVE_MODAL_ID } from '../constants'; - -export default { - name: 'LeaveButton', - title: __('Leave'), - modalId: LEAVE_MODAL_ID, - components: { - GlButton, - LeaveModal, - }, - directives: { - GlModal: GlModalDirective, - GlTooltip: GlTooltipDirective, - }, - props: { - member: { - type: Object, - required: true, - }, - }, -}; -</script> - -<template> - <div> - <gl-button - v-gl-tooltip.hover - v-gl-modal="$options.modalId" - :title="$options.title" - :aria-label="$options.title" - icon="leave" - variant="danger" - /> - <leave-modal :member="member" /> - </div> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_group_link_button.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_group_link_button.vue deleted file mode 100644 index 9d89cb40676..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_group_link_button.vue +++ /dev/null @@ -1,36 +0,0 @@ -<script> -import { mapActions } from 'vuex'; -import { GlButton, GlTooltipDirective } from '@gitlab/ui'; -import { s__ } from '~/locale'; - -export default { - name: 'RemoveGroupLinkButton', - i18n: { - buttonTitle: s__('Members|Remove group'), - }, - components: { GlButton }, - directives: { - GlTooltip: GlTooltipDirective, - }, - props: { - groupLink: { - type: Object, - required: true, - }, - }, - methods: { - ...mapActions(['showRemoveGroupLinkModal']), - }, -}; -</script> - -<template> - <gl-button - v-gl-tooltip.hover - variant="danger" - :title="$options.i18n.buttonTitle" - :aria-label="$options.i18n.buttonTitle" - icon="remove" - @click="showRemoveGroupLinkModal(groupLink)" - /> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_member_button.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_member_button.vue deleted file mode 100644 index b0b7ff4ce9a..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_member_button.vue +++ /dev/null @@ -1,57 +0,0 @@ -<script> -import { mapState } from 'vuex'; -import { GlButton, GlTooltipDirective } from '@gitlab/ui'; - -export default { - name: 'RemoveMemberButton', - components: { GlButton }, - directives: { - GlTooltip: GlTooltipDirective, - }, - props: { - memberId: { - type: Number, - required: true, - }, - message: { - type: String, - required: true, - }, - title: { - type: String, - required: true, - }, - icon: { - type: String, - required: false, - default: 'remove', - }, - isAccessRequest: { - type: Boolean, - required: false, - default: false, - }, - }, - computed: { - ...mapState(['memberPath']), - computedMemberPath() { - return this.memberPath.replace(':id', this.memberId); - }, - }, -}; -</script> - -<template> - <gl-button - v-gl-tooltip.hover - class="js-remove-member-button" - variant="danger" - :title="title" - :aria-label="title" - :icon="icon" - :data-member-path="computedMemberPath" - :data-is-access-request="isAccessRequest" - :data-message="message" - data-qa-selector="delete_member_button" - /> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/resend_invite_button.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/resend_invite_button.vue deleted file mode 100644 index 1cc3fd17e98..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/action_buttons/resend_invite_button.vue +++ /dev/null @@ -1,41 +0,0 @@ -<script> -import { mapState } from 'vuex'; -import { GlButton, GlTooltipDirective } from '@gitlab/ui'; -import csrf from '~/lib/utils/csrf'; -import { __ } from '~/locale'; - -export default { - name: 'ResendInviteButton', - csrf, - title: __('Resend invite'), - components: { GlButton }, - directives: { - GlTooltip: GlTooltipDirective, - }, - props: { - memberId: { - type: Number, - required: true, - }, - }, - computed: { - ...mapState(['memberPath']), - resendPath() { - return this.memberPath.replace(/:id$/, `${this.memberId}/resend_invite`); - }, - }, -}; -</script> - -<template> - <form :action="resendPath" method="post"> - <input :value="$options.csrf.token" type="hidden" name="authenticity_token" /> - <gl-button - v-gl-tooltip.hover - :title="$options.title" - :aria-label="$options.title" - icon="paper-airplane" - type="submit" - /> - </form> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue deleted file mode 100644 index 484dbb8fef5..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue +++ /dev/null @@ -1,70 +0,0 @@ -<script> -import ActionButtonGroup from './action_button_group.vue'; -import RemoveMemberButton from './remove_member_button.vue'; -import LeaveButton from './leave_button.vue'; -import { s__, sprintf } from '~/locale'; - -export default { - name: 'UserActionButtons', - components: { - ActionButtonGroup, - RemoveMemberButton, - LeaveButton, - LdapOverrideButton: () => - import('ee_component/vue_shared/components/members/ldap/ldap_override_button.vue'), - }, - props: { - member: { - type: Object, - required: true, - }, - isCurrentUser: { - type: Boolean, - required: true, - }, - permissions: { - type: Object, - required: true, - }, - }, - computed: { - message() { - const { user, source } = this.member; - - if (user) { - return sprintf( - s__('Members|Are you sure you want to remove %{usersName} from "%{source}"'), - { - usersName: user.name, - source: source.name, - }, - ); - } - - return sprintf( - s__('Members|Are you sure you want to remove this orphaned member from "%{source}"'), - { - source: source.name, - }, - ); - }, - }, -}; -</script> - -<template> - <action-button-group> - <div v-if="permissions.canRemove" class="gl-px-1"> - <leave-button v-if="isCurrentUser" :member="member" /> - <remove-member-button - v-else - :member-id="member.id" - :message="message" - :title="s__('Member|Remove member')" - /> - </div> - <div v-else-if="permissions.canOverride && !member.isOverridden" class="gl-px-1"> - <ldap-override-button :member="member" /> - </div> - </action-button-group> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/avatars/group_avatar.vue b/app/assets/javascripts/vue_shared/components/members/avatars/group_avatar.vue deleted file mode 100644 index 12b748f9ab6..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/avatars/group_avatar.vue +++ /dev/null @@ -1,34 +0,0 @@ -<script> -import { GlAvatarLink, GlAvatarLabeled } from '@gitlab/ui'; -import { AVATAR_SIZE } from '../constants'; - -export default { - name: 'GroupAvatar', - avatarSize: AVATAR_SIZE, - components: { GlAvatarLink, GlAvatarLabeled }, - props: { - member: { - type: Object, - required: true, - }, - }, - computed: { - group() { - return this.member.sharedWithGroup; - }, - }, -}; -</script> - -<template> - <gl-avatar-link :href="group.webUrl"> - <gl-avatar-labeled - :label="group.fullName" - :src="group.avatarUrl" - :alt="group.fullName" - :size="$options.avatarSize" - :entity-name="group.name" - :entity-id="group.id" - /> - </gl-avatar-link> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/avatars/invite_avatar.vue b/app/assets/javascripts/vue_shared/components/members/avatars/invite_avatar.vue deleted file mode 100644 index 28654a60860..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/avatars/invite_avatar.vue +++ /dev/null @@ -1,32 +0,0 @@ -<script> -import { GlAvatarLabeled } from '@gitlab/ui'; -import { AVATAR_SIZE } from '../constants'; - -export default { - name: 'InviteAvatar', - avatarSize: AVATAR_SIZE, - components: { GlAvatarLabeled }, - props: { - member: { - type: Object, - required: true, - }, - }, - computed: { - invite() { - return this.member.invite; - }, - }, -}; -</script> - -<template> - <gl-avatar-labeled - :label="invite.email" - :src="invite.avatarUrl" - :alt="invite.email" - :size="$options.avatarSize" - :entity-name="invite.email" - :entity-id="member.id" - /> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/avatars/user_avatar.vue b/app/assets/javascripts/vue_shared/components/members/avatars/user_avatar.vue deleted file mode 100644 index e5e7cdf149c..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/avatars/user_avatar.vue +++ /dev/null @@ -1,91 +0,0 @@ -<script> -import { - GlAvatarLink, - GlAvatarLabeled, - GlBadge, - GlSafeHtmlDirective as SafeHtml, -} from '@gitlab/ui'; -import { generateBadges } from 'ee_else_ce/vue_shared/components/members/utils'; -import { __ } from '~/locale'; -import { AVATAR_SIZE } from '../constants'; -import { glEmojiTag } from '~/emoji'; - -export default { - name: 'UserAvatar', - avatarSize: AVATAR_SIZE, - orphanedUserLabel: __('Orphaned member'), - safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] }, - components: { - GlAvatarLink, - GlAvatarLabeled, - GlBadge, - }, - directives: { - SafeHtml, - }, - props: { - member: { - type: Object, - required: true, - }, - isCurrentUser: { - type: Boolean, - required: true, - }, - }, - computed: { - user() { - return this.member.user; - }, - badges() { - return generateBadges(this.member, this.isCurrentUser).filter(badge => badge.show); - }, - statusEmoji() { - return this.user?.status?.emoji; - }, - }, - methods: { - glEmojiTag, - }, -}; -</script> - -<template> - <gl-avatar-link - v-if="user" - class="js-user-link" - :href="user.webUrl" - :data-user-id="user.id" - :data-username="user.username" - > - <gl-avatar-labeled - :label="user.name" - :sub-label="`@${user.username}`" - :src="user.avatarUrl" - :alt="user.name" - :size="$options.avatarSize" - :entity-name="user.name" - :entity-id="user.id" - > - <template #meta> - <div v-if="statusEmoji" class="gl-p-1"> - <span v-safe-html:[$options.safeHtmlConfig]="glEmojiTag(statusEmoji)"></span> - </div> - <div v-for="badge in badges" :key="badge.text" class="gl-p-1"> - <gl-badge size="sm" :variant="badge.variant"> - {{ badge.text }} - </gl-badge> - </div> - </template> - </gl-avatar-labeled> - </gl-avatar-link> - - <gl-avatar-labeled - v-else - :label="$options.orphanedUserLabel" - :alt="$options.orphanedUserLabel" - :size="$options.avatarSize" - :entity-name="$options.orphanedUserLabel" - :entity-id="member.id" - /> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/constants.js b/app/assets/javascripts/vue_shared/components/members/constants.js deleted file mode 100644 index 5885420a122..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/constants.js +++ /dev/null @@ -1,71 +0,0 @@ -import { __ } from '~/locale'; - -export const FIELDS = [ - { - key: 'account', - label: __('Account'), - }, - { - key: 'source', - label: __('Source'), - thClass: 'col-meta', - tdClass: 'col-meta', - }, - { - key: 'granted', - label: __('Access granted'), - thClass: 'col-meta', - tdClass: 'col-meta', - }, - { - key: 'invited', - label: __('Invited'), - thClass: 'col-meta', - tdClass: 'col-meta', - }, - { - key: 'requested', - label: __('Requested'), - thClass: 'col-meta', - tdClass: 'col-meta', - }, - { - key: 'expires', - label: __('Access expires'), - thClass: 'col-meta', - tdClass: 'col-meta', - }, - { - key: 'maxRole', - label: __('Max role'), - thClass: 'col-max-role', - tdClass: 'col-max-role', - }, - { - key: 'expiration', - label: __('Expiration'), - thClass: 'col-expiration', - tdClass: 'col-expiration', - }, - { - key: 'actions', - thClass: 'col-actions', - tdClass: 'col-actions', - showFunction: 'showActionsField', - }, -]; - -export const AVATAR_SIZE = 48; - -export const MEMBER_TYPES = { - user: 'user', - group: 'group', - invite: 'invite', - accessRequest: 'accessRequest', -}; - -export const DAYS_TO_EXPIRE_SOON = 7; - -export const LEAVE_MODAL_ID = 'member-leave-modal'; - -export const REMOVE_GROUP_LINK_MODAL_ID = 'remove-group-link-modal-id'; diff --git a/app/assets/javascripts/vue_shared/components/members/modals/leave_modal.vue b/app/assets/javascripts/vue_shared/components/members/modals/leave_modal.vue deleted file mode 100644 index 9a2ce0d4931..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/modals/leave_modal.vue +++ /dev/null @@ -1,70 +0,0 @@ -<script> -import { mapState } from 'vuex'; -import { GlModal, GlForm, GlSprintf, GlTooltipDirective } from '@gitlab/ui'; -import csrf from '~/lib/utils/csrf'; -import { __, s__, sprintf } from '~/locale'; -import { LEAVE_MODAL_ID } from '../constants'; - -export default { - name: 'LeaveModal', - actionCancel: { - text: __('Cancel'), - }, - actionPrimary: { - text: __('Leave'), - attributes: { - variant: 'danger', - }, - }, - csrf, - modalId: LEAVE_MODAL_ID, - modalContent: s__('Members|Are you sure you want to leave "%{source}"?'), - components: { GlModal, GlForm, GlSprintf }, - directives: { - GlTooltip: GlTooltipDirective, - }, - props: { - member: { - type: Object, - required: true, - }, - }, - computed: { - ...mapState(['memberPath']), - leavePath() { - return this.memberPath.replace(/:id$/, 'leave'); - }, - modalTitle() { - return sprintf(s__('Members|Leave "%{source}"'), { source: this.member.source.name }); - }, - }, - methods: { - handlePrimary() { - this.$refs.form.$el.submit(); - }, - }, -}; -</script> - -<template> - <gl-modal - v-bind="$attrs" - :modal-id="$options.modalId" - :title="modalTitle" - :action-primary="$options.actionPrimary" - :action-cancel="$options.actionCancel" - size="sm" - @primary="handlePrimary" - > - <gl-form ref="form" :action="leavePath" method="post"> - <p> - <gl-sprintf :message="$options.modalContent"> - <template #source>{{ member.source.name }}</template> - </gl-sprintf> - </p> - - <input type="hidden" name="_method" value="delete" /> - <input :value="$options.csrf.token" type="hidden" name="authenticity_token" /> - </gl-form> - </gl-modal> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/modals/remove_group_link_modal.vue b/app/assets/javascripts/vue_shared/components/members/modals/remove_group_link_modal.vue deleted file mode 100644 index e8890717724..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/modals/remove_group_link_modal.vue +++ /dev/null @@ -1,69 +0,0 @@ -<script> -import { mapState, mapActions } from 'vuex'; -import { GlModal, GlSprintf, GlForm } from '@gitlab/ui'; -import csrf from '~/lib/utils/csrf'; -import { __, s__, sprintf } from '~/locale'; -import { REMOVE_GROUP_LINK_MODAL_ID } from '../constants'; - -export default { - name: 'RemoveGroupLinkModal', - actionCancel: { - text: __('Cancel'), - }, - actionPrimary: { - text: s__('Members|Remove group'), - attributes: { - variant: 'danger', - }, - }, - csrf, - i18n: { - modalBody: s__('Members|Are you sure you want to remove "%{groupName}"?'), - }, - modalId: REMOVE_GROUP_LINK_MODAL_ID, - components: { GlModal, GlSprintf, GlForm }, - computed: { - ...mapState(['memberPath', 'groupLinkToRemove', 'removeGroupLinkModalVisible']), - groupLinkPath() { - return this.memberPath.replace(/:id$/, this.groupLinkToRemove?.id); - }, - groupName() { - return this.groupLinkToRemove?.sharedWithGroup.fullName; - }, - modalTitle() { - return sprintf(s__('Members|Remove "%{groupName}"'), { groupName: this.groupName }); - }, - }, - methods: { - ...mapActions(['hideRemoveGroupLinkModal']), - handlePrimary() { - this.$refs.form.$el.submit(); - }, - }, -}; -</script> - -<template> - <gl-modal - v-bind="$attrs" - :modal-id="$options.modalId" - :visible="removeGroupLinkModalVisible" - :title="modalTitle" - :action-primary="$options.actionPrimary" - :action-cancel="$options.actionCancel" - size="sm" - @primary="handlePrimary" - @hide="hideRemoveGroupLinkModal" - > - <gl-form ref="form" :action="groupLinkPath" method="post"> - <p> - <gl-sprintf :message="$options.i18n.modalBody"> - <template #groupName>{{ groupName }}</template> - </gl-sprintf> - </p> - - <input type="hidden" name="_method" value="delete" /> - <input :value="$options.csrf.token" type="hidden" name="authenticity_token" /> - </gl-form> - </gl-modal> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/table/created_at.vue b/app/assets/javascripts/vue_shared/components/members/table/created_at.vue deleted file mode 100644 index 0bad70894f9..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/table/created_at.vue +++ /dev/null @@ -1,40 +0,0 @@ -<script> -import { GlSprintf } from '@gitlab/ui'; -import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; - -export default { - name: 'CreatedAt', - components: { GlSprintf, TimeAgoTooltip }, - props: { - date: { - type: String, - required: false, - default: null, - }, - createdBy: { - type: Object, - required: false, - default: null, - }, - }, - computed: { - showCreatedBy() { - return this.createdBy?.name && this.createdBy?.webUrl; - }, - }, -}; -</script> - -<template> - <span> - <gl-sprintf v-if="showCreatedBy" :message="s__('Members|%{time} by %{user}')"> - <template #time> - <time-ago-tooltip :time="date" /> - </template> - <template #user> - <a :href="createdBy.webUrl">{{ createdBy.name }}</a> - </template> - </gl-sprintf> - <time-ago-tooltip v-else :time="date" /> - </span> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/table/expiration_datepicker.vue b/app/assets/javascripts/vue_shared/components/members/table/expiration_datepicker.vue deleted file mode 100644 index 0a8af81c1d1..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/table/expiration_datepicker.vue +++ /dev/null @@ -1,99 +0,0 @@ -<script> -import { GlDatepicker } from '@gitlab/ui'; -import { mapActions } from 'vuex'; -import { getDateInFuture } from '~/lib/utils/datetime_utility'; -import { s__ } from '~/locale'; - -export default { - name: 'ExpirationDatepicker', - components: { GlDatepicker }, - props: { - member: { - type: Object, - required: true, - }, - permissions: { - type: Object, - required: true, - }, - }, - data() { - return { - selectedDate: null, - busy: false, - }; - }, - computed: { - minDate() { - // Members expire at the beginning of the day. - // The first selectable day should be tomorrow. - const today = new Date(); - const beginningOfToday = new Date(today.setHours(0, 0, 0, 0)); - - return getDateInFuture(beginningOfToday, 1); - }, - disabled() { - return ( - this.busy || - !this.permissions.canUpdate || - (this.permissions.canOverride && !this.member.isOverridden) - ); - }, - }, - mounted() { - if (this.member.expiresAt) { - this.selectedDate = new Date(this.member.expiresAt); - } - }, - methods: { - ...mapActions(['updateMemberExpiration']), - handleInput(date) { - this.busy = true; - this.updateMemberExpiration({ - memberId: this.member.id, - expiresAt: date, - }) - .then(() => { - this.$toast.show(s__('Members|Expiration date updated successfully.')); - this.busy = false; - }) - .catch(() => { - this.busy = false; - }); - }, - handleClear() { - this.busy = true; - - this.updateMemberExpiration({ - memberId: this.member.id, - expiresAt: null, - }) - .then(() => { - this.$toast.show(s__('Members|Expiration date removed successfully.')); - this.selectedDate = null; - this.busy = false; - }) - .catch(() => { - this.busy = false; - }); - }, - }, -}; -</script> - -<template> - <!-- `:target="null"` allows the datepicker to be opened on focus --> - <!-- `:container="null"` renders the datepicker in the body to prevent conflicting CSS table styles --> - <gl-datepicker - v-model="selectedDate" - class="gl-max-w-full" - show-clear-button - :target="null" - :container="null" - :min-date="minDate" - :placeholder="__('Expiration date')" - :disabled="disabled" - @input="handleInput" - @clear="handleClear" - /> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/table/expires_at.vue b/app/assets/javascripts/vue_shared/components/members/table/expires_at.vue deleted file mode 100644 index de65e3fb10f..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/table/expires_at.vue +++ /dev/null @@ -1,66 +0,0 @@ -<script> -import { GlSprintf, GlTooltipDirective } from '@gitlab/ui'; -import { - approximateDuration, - differenceInSeconds, - formatDate, - getDayDifference, -} from '~/lib/utils/datetime_utility'; -import { DAYS_TO_EXPIRE_SOON } from '../constants'; - -export default { - name: 'ExpiresAt', - components: { GlSprintf }, - directives: { - GlTooltip: GlTooltipDirective, - }, - props: { - date: { - type: String, - required: false, - default: null, - }, - }, - computed: { - noExpirationSet() { - return this.date === null; - }, - parsed() { - return new Date(this.date); - }, - differenceInSeconds() { - return differenceInSeconds(new Date(), this.parsed); - }, - isExpired() { - return this.differenceInSeconds <= 0; - }, - inWords() { - return approximateDuration(this.differenceInSeconds); - }, - formatted() { - return formatDate(this.parsed); - }, - expiresSoon() { - return getDayDifference(new Date(), this.parsed) < DAYS_TO_EXPIRE_SOON; - }, - cssClass() { - return { - 'gl-text-red-500': this.isExpired, - 'gl-text-orange-500': this.expiresSoon, - }; - }, - }, -}; -</script> - -<template> - <span v-if="noExpirationSet">{{ s__('Members|No expiration set') }}</span> - <span v-else v-gl-tooltip.hover :title="formatted" :class="cssClass"> - <template v-if="isExpired">{{ s__('Members|Expired') }}</template> - <gl-sprintf v-else :message="s__('Members|in %{time}')"> - <template #time> - {{ inWords }} - </template> - </gl-sprintf> - </span> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/table/member_action_buttons.vue b/app/assets/javascripts/vue_shared/components/members/table/member_action_buttons.vue deleted file mode 100644 index 320d8c99223..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/table/member_action_buttons.vue +++ /dev/null @@ -1,57 +0,0 @@ -<script> -import UserActionButtons from '../action_buttons/user_action_buttons.vue'; -import GroupActionButtons from '../action_buttons/group_action_buttons.vue'; -import InviteActionButtons from '../action_buttons/invite_action_buttons.vue'; -import AccessRequestActionButtons from '../action_buttons/access_request_action_buttons.vue'; -import { MEMBER_TYPES } from '../constants'; - -export default { - name: 'MemberActionButtons', - components: { - UserActionButtons, - GroupActionButtons, - InviteActionButtons, - AccessRequestActionButtons, - }, - props: { - member: { - type: Object, - required: true, - }, - memberType: { - type: String, - required: true, - }, - permissions: { - type: Object, - required: true, - }, - isCurrentUser: { - type: Boolean, - required: true, - }, - }, - computed: { - actionButtonComponent() { - const dictionary = { - [MEMBER_TYPES.user]: 'user-action-buttons', - [MEMBER_TYPES.group]: 'group-action-buttons', - [MEMBER_TYPES.invite]: 'invite-action-buttons', - [MEMBER_TYPES.accessRequest]: 'access-request-action-buttons', - }; - - return dictionary[this.memberType]; - }, - }, -}; -</script> - -<template> - <component - :is="actionButtonComponent" - v-if="actionButtonComponent" - :member="member" - :permissions="permissions" - :is-current-user="isCurrentUser" - /> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/table/member_avatar.vue b/app/assets/javascripts/vue_shared/components/members/table/member_avatar.vue deleted file mode 100644 index a1f98d4008a..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/table/member_avatar.vue +++ /dev/null @@ -1,35 +0,0 @@ -<script> -import { kebabCase } from 'lodash'; -import UserAvatar from '../avatars/user_avatar.vue'; -import InviteAvatar from '../avatars/invite_avatar.vue'; -import GroupAvatar from '../avatars/group_avatar.vue'; - -export default { - name: 'MemberAvatar', - components: { UserAvatar, InviteAvatar, GroupAvatar, AccessRequestAvatar: UserAvatar }, - props: { - memberType: { - type: String, - required: true, - }, - isCurrentUser: { - type: Boolean, - required: true, - }, - member: { - type: Object, - required: true, - }, - }, - computed: { - avatarComponent() { - // eslint-disable-next-line @gitlab/require-i18n-strings - return `${kebabCase(this.memberType)}-avatar`; - }, - }, -}; -</script> - -<template> - <component :is="avatarComponent" :member="member" :is-current-user="isCurrentUser" /> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/table/member_source.vue b/app/assets/javascripts/vue_shared/components/members/table/member_source.vue deleted file mode 100644 index 030d72c3420..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/table/member_source.vue +++ /dev/null @@ -1,27 +0,0 @@ -<script> -import { GlTooltipDirective } from '@gitlab/ui'; - -export default { - name: 'MemberSource', - directives: { - GlTooltip: GlTooltipDirective, - }, - props: { - memberSource: { - type: Object, - required: true, - }, - isDirectMember: { - type: Boolean, - required: true, - }, - }, -}; -</script> - -<template> - <span v-if="isDirectMember">{{ __('Direct member') }}</span> - <a v-else v-gl-tooltip.hover :title="__('Inherited')" :href="memberSource.webUrl">{{ - memberSource.name - }}</a> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/table/members_table.vue b/app/assets/javascripts/vue_shared/components/members/table/members_table.vue deleted file mode 100644 index a4f67caff31..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/table/members_table.vue +++ /dev/null @@ -1,158 +0,0 @@ -<script> -import { mapState } from 'vuex'; -import { GlTable, GlBadge } from '@gitlab/ui'; -import MembersTableCell from 'ee_else_ce/vue_shared/components/members/table/members_table_cell.vue'; -import { - canOverride, - canRemove, - canResend, - canUpdate, -} from 'ee_else_ce/vue_shared/components/members/utils'; -import { FIELDS } from '../constants'; -import initUserPopovers from '~/user_popovers'; -import MemberAvatar from './member_avatar.vue'; -import MemberSource from './member_source.vue'; -import CreatedAt from './created_at.vue'; -import ExpiresAt from './expires_at.vue'; -import MemberActionButtons from './member_action_buttons.vue'; -import RoleDropdown from './role_dropdown.vue'; -import RemoveGroupLinkModal from '../modals/remove_group_link_modal.vue'; -import ExpirationDatepicker from './expiration_datepicker.vue'; - -export default { - name: 'MembersTable', - components: { - GlTable, - GlBadge, - MemberAvatar, - CreatedAt, - ExpiresAt, - MembersTableCell, - MemberSource, - MemberActionButtons, - RoleDropdown, - RemoveGroupLinkModal, - ExpirationDatepicker, - LdapOverrideConfirmationModal: () => - import( - 'ee_component/vue_shared/components/members/ldap/ldap_override_confirmation_modal.vue' - ), - }, - computed: { - ...mapState(['members', 'tableFields', 'tableAttrs', 'currentUserId', 'sourceId']), - filteredFields() { - return FIELDS.filter(field => this.tableFields.includes(field.key) && this.showField(field)); - }, - userIsLoggedIn() { - return this.currentUserId !== null; - }, - }, - mounted() { - initUserPopovers(this.$el.querySelectorAll('.js-user-link')); - }, - methods: { - showField(field) { - if (!Object.prototype.hasOwnProperty.call(field, 'showFunction')) { - return true; - } - - return this[field.showFunction](); - }, - showActionsField() { - if (!this.userIsLoggedIn) { - return false; - } - - return this.members.some(member => { - return ( - canRemove(member, this.sourceId) || - canResend(member) || - canUpdate(member, this.currentUserId, this.sourceId) || - canOverride(member) - ); - }); - }, - }, -}; -</script> - -<template> - <div> - <gl-table - v-bind="tableAttrs.table" - class="members-table" - data-testid="members-table" - head-variant="white" - stacked="lg" - :fields="filteredFields" - :items="members" - primary-key="id" - thead-class="border-bottom" - :empty-text="__('No members found')" - show-empty - :tbody-tr-attr="tableAttrs.tr" - > - <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> - - <template #cell(invited)="{ item: { createdAt, createdBy } }"> - <created-at :date="createdAt" :created-by="createdBy" /> - </template> - - <template #cell(requested)="{ item: { createdAt } }"> - <created-at :date="createdAt" /> - </template> - - <template #cell(expires)="{ item: { expiresAt } }"> - <expires-at :date="expiresAt" /> - </template> - - <template #cell(maxRole)="{ item: member }"> - <members-table-cell #default="{ permissions }" :member="member"> - <role-dropdown v-if="permissions.canUpdate" :permissions="permissions" :member="member" /> - <gl-badge v-else>{{ member.accessLevel.stringValue }}</gl-badge> - </members-table-cell> - </template> - - <template #cell(expiration)="{ item: member }"> - <members-table-cell #default="{ permissions }" :member="member"> - <expiration-datepicker :permissions="permissions" :member="member" /> - </members-table-cell> - </template> - - <template #cell(actions)="{ item: member }"> - <members-table-cell #default="{ memberType, isCurrentUser, permissions }" :member="member"> - <member-action-buttons - :member-type="memberType" - :is-current-user="isCurrentUser" - :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> - <remove-group-link-modal /> - <ldap-override-confirmation-modal /> - </div> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/table/members_table_cell.vue b/app/assets/javascripts/vue_shared/components/members/table/members_table_cell.vue deleted file mode 100644 index 11e1aef9803..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/table/members_table_cell.vue +++ /dev/null @@ -1,65 +0,0 @@ -<script> -import { mapState } from 'vuex'; -import { MEMBER_TYPES } from '../constants'; -import { isGroup, isDirectMember, isCurrentUser, canRemove, canResend, canUpdate } from '../utils'; - -export default { - name: 'MembersTableCell', - props: { - member: { - type: Object, - required: true, - }, - }, - computed: { - ...mapState(['sourceId', 'currentUserId']), - isGroup() { - return isGroup(this.member); - }, - isInvite() { - return Boolean(this.member.invite); - }, - isAccessRequest() { - return Boolean(this.member.requestedAt); - }, - memberType() { - if (this.isGroup) { - return MEMBER_TYPES.group; - } else if (this.isInvite) { - return MEMBER_TYPES.invite; - } else if (this.isAccessRequest) { - return MEMBER_TYPES.accessRequest; - } - - return MEMBER_TYPES.user; - }, - isDirectMember() { - return isDirectMember(this.member, this.sourceId); - }, - isCurrentUser() { - return isCurrentUser(this.member, this.currentUserId); - }, - canRemove() { - return canRemove(this.member, this.sourceId); - }, - canResend() { - return canResend(this.member); - }, - canUpdate() { - return canUpdate(this.member, this.currentUserId, this.sourceId); - }, - }, - render() { - return this.$scopedSlots.default({ - memberType: this.memberType, - isDirectMember: this.isDirectMember, - isCurrentUser: this.isCurrentUser, - permissions: { - canRemove: this.canRemove, - canResend: this.canResend, - canUpdate: this.canUpdate, - }, - }); - }, -}; -</script> diff --git a/app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue b/app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue deleted file mode 100644 index 6f6cae6072d..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue +++ /dev/null @@ -1,95 +0,0 @@ -<script> -import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; -import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils'; -import { mapActions } from 'vuex'; -import { s__ } from '~/locale'; - -export default { - name: 'RoleDropdown', - components: { - GlDropdown, - GlDropdownItem, - LdapDropdownItem: () => - import('ee_component/vue_shared/components/members/ldap/ldap_dropdown_item.vue'), - }, - props: { - member: { - type: Object, - required: true, - }, - permissions: { - type: Object, - required: true, - }, - }, - data() { - return { - isDesktop: false, - busy: false, - }; - }, - computed: { - disabled() { - return this.busy || (this.permissions.canOverride && !this.member.isOverridden); - }, - }, - mounted() { - this.isDesktop = bp.isDesktop(); - - // Bootstrap Vue and GlDropdown to not support adding attributes to the dropdown toggle - // This can be changed once https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1060 is implemented - const dropdownToggle = this.$refs.glDropdown.$el.querySelector('.dropdown-toggle'); - - if (dropdownToggle) { - dropdownToggle.setAttribute('data-qa-selector', 'access_level_dropdown'); - } - }, - methods: { - ...mapActions(['updateMemberRole']), - handleSelect(value, name) { - if (value === this.member.accessLevel.integerValue) { - return; - } - - this.busy = true; - - this.updateMemberRole({ - memberId: this.member.id, - accessLevel: { integerValue: value, stringValue: name }, - }) - .then(() => { - this.$toast.show(s__('Members|Role updated successfully.')); - this.busy = false; - }) - .catch(() => { - this.busy = false; - }); - }, - }, -}; -</script> - -<template> - <gl-dropdown - ref="glDropdown" - :right="!isDesktop" - :text="member.accessLevel.stringValue" - :header-text="__('Change permissions')" - :disabled="disabled" - > - <gl-dropdown-item - v-for="(value, name) in member.validRoles" - :key="value" - is-check-item - :is-checked="value === member.accessLevel.integerValue" - data-qa-selector="access_level_link" - @click="handleSelect(value, name)" - > - {{ name }} - </gl-dropdown-item> - <ldap-dropdown-item - v-if="permissions.canOverride && member.isOverridden" - :member-id="member.id" - /> - </gl-dropdown> -</template> diff --git a/app/assets/javascripts/vue_shared/components/members/utils.js b/app/assets/javascripts/vue_shared/components/members/utils.js deleted file mode 100644 index 4229a62c0a7..00000000000 --- a/app/assets/javascripts/vue_shared/components/members/utils.js +++ /dev/null @@ -1,48 +0,0 @@ -import { __ } from '~/locale'; - -export const generateBadges = (member, isCurrentUser) => [ - { - show: isCurrentUser, - text: __("It's you"), - variant: 'success', - }, - { - show: member.user?.blocked, - text: __('Blocked'), - variant: 'danger', - }, - { - show: member.user?.twoFactorEnabled, - text: __('2FA'), - variant: 'info', - }, -]; - -export const isGroup = member => { - return Boolean(member.sharedWithGroup); -}; - -export const isDirectMember = (member, sourceId) => { - return isGroup(member) || member.source?.id === sourceId; -}; - -export const isCurrentUser = (member, currentUserId) => { - return member.user?.id === currentUserId; -}; - -export const canRemove = (member, sourceId) => { - return isDirectMember(member, sourceId) && member.canRemove; -}; - -export const canResend = member => { - return Boolean(member.invite?.canResend); -}; - -export const canUpdate = (member, currentUserId, sourceId) => { - return ( - !isCurrentUser(member, currentUserId) && isDirectMember(member, sourceId) && member.canUpdate - ); -}; - -// Defined in `ee/app/assets/javascripts/vue_shared/components/members/utils.js` -export const canOverride = () => false; |