diff --git a/.rubocop_todo/rspec/verified_doubles.yml b/.rubocop_todo/rspec/verified_doubles.yml index 84e862ff48b..70b54d5bc7f 100644 --- a/.rubocop_todo/rspec/verified_doubles.yml +++ b/.rubocop_todo/rspec/verified_doubles.yml @@ -210,6 +210,7 @@ RSpec/VerifiedDoubles: - ee/spec/views/layouts/header/_ee_subscribable_banner.html.haml_spec.rb - ee/spec/workers/ci/sync_reports_to_report_approval_rules_worker_spec.rb - ee/spec/workers/geo/container_repository_sync_worker_spec.rb + - ee/spec/workers/compliance_management/chain_of_custody_report_worker_spec.rb - ee/spec/workers/geo/design_repository_sync_worker_spec.rb - ee/spec/workers/geo/destroy_worker_spec.rb - ee/spec/workers/geo/event_worker_spec.rb diff --git a/app/assets/javascripts/invite_members/components/invite_members_modal.vue b/app/assets/javascripts/invite_members/components/invite_members_modal.vue index 674058bcaf0..87f1ed31a7f 100644 --- a/app/assets/javascripts/invite_members/components/invite_members_modal.vue +++ b/app/assets/javascripts/invite_members/components/invite_members_modal.vue @@ -6,6 +6,9 @@ import { GlLink, GlSprintf, GlFormCheckboxGroup, + GlButton, + GlCollapse, + GlIcon, } from '@gitlab/ui'; import { partition, isString, uniqueId, isEmpty } from 'lodash'; import InviteModalBase from 'ee_else_ce/invite_members/components/invite_modal_base.vue'; @@ -13,7 +16,7 @@ import Api from '~/api'; import ExperimentTracking from '~/experimentation/experiment_tracking'; import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants'; import { getParameterValues } from '~/lib/utils/url_utility'; -import { n__ } from '~/locale'; +import { n__, sprintf } from '~/locale'; import { CLOSE_TO_LIMIT_COUNT, USERS_FILTER_ALL, @@ -38,6 +41,9 @@ export default { GlDropdownItem, GlSprintf, GlFormCheckboxGroup, + GlButton, + GlCollapse, + GlIcon, InviteModalBase, MembersTokenSelect, ModalConfetti, @@ -110,6 +116,8 @@ export default { mode: 'default', // Kept in sync with "base" selectedAccessLevel: undefined, + errorsLimit: 2, + isErrorsSectionExpanded: false, }; }, computed: { @@ -135,7 +143,7 @@ export default { return n__( "InviteMembersModal|The following member couldn't be invited", "InviteMembersModal|The following %d members couldn't be invited", - Object.keys(this.invalidMembers).length, + this.errorList.length, ); }, tasksToBeDoneEnabled() { @@ -187,6 +195,29 @@ export default { ? this.$options.labels.placeHolderDisabled : this.$options.labels.placeHolder; }, + errorList() { + return Object.entries(this.invalidMembers).map(([member, error]) => { + return { member, displayedMemberName: this.tokenName(member), message: error }; + }); + }, + errorsLimited() { + return this.errorList.slice(0, this.errorsLimit); + }, + errorsExpanded() { + return this.errorList.slice(this.errorsLimit); + }, + shouldErrorsSectionExpand() { + return Boolean(this.errorsExpanded.length); + }, + errorCollapseText() { + if (this.isErrorsSectionExpanded) { + return this.$options.labels.expandedErrors; + } + + return sprintf(this.$options.labels.collapsedErrors, { + count: this.errorsExpanded.length, + }); + }, }, mounted() { eventHub.$on('openModal', (options) => { @@ -311,6 +342,9 @@ export default { delete this.invalidMembers[memberName(token)]; this.invalidMembers = { ...this.invalidMembers }; }, + toggleErrorExpansion() { + this.isErrorsSectionExpanded = !this.isErrorsSectionExpanded; + }, }, labels: MEMBER_MODAL_LABELS, }; @@ -357,10 +391,36 @@ export default { > {{ $options.labels.memberErrorListText }} +