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:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-08-18 11:17:02 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-08-18 11:17:02 +0300
commitb39512ed755239198a9c294b6a45e65c05900235 (patch)
treed234a3efade1de67c46b9e5a38ce813627726aa7 /app/assets/javascripts/invite_members
parentd31474cf3b17ece37939d20082b07f6657cc79a9 (diff)
Add latest changes from gitlab-org/gitlab@15-3-stable-eev15.3.0-rc42
Diffstat (limited to 'app/assets/javascripts/invite_members')
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_modal.vue70
-rw-r--r--app/assets/javascripts/invite_members/components/members_token_select.vue43
-rw-r--r--app/assets/javascripts/invite_members/components/user_limit_notification.vue8
-rw-r--r--app/assets/javascripts/invite_members/constants.js13
-rw-r--r--app/assets/javascripts/invite_members/init_invite_members_modal.js9
5 files changed, 120 insertions, 23 deletions
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 b71cfbb6112..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,
};
@@ -356,11 +390,37 @@ export default {
data-testid="alert-member-error"
>
{{ $options.labels.memberErrorListText }}
- <ul class="gl-pl-5">
- <li v-for="(error, member) in invalidMembers" :key="member">
- <strong>{{ tokenName(member) }}:</strong> {{ error }}
+ <ul class="gl-pl-5 gl-mb-0">
+ <li v-for="error in errorsLimited" :key="error.member" data-testid="errors-limited-item">
+ <strong>{{ error.displayedMemberName }}:</strong> {{ error.message }}
</li>
</ul>
+ <template v-if="shouldErrorsSectionExpand">
+ <gl-collapse v-model="isErrorsSectionExpanded">
+ <ul class="gl-pl-5 gl-mb-0">
+ <li
+ v-for="error in errorsExpanded"
+ :key="error.member"
+ data-testid="errors-expanded-item"
+ >
+ <strong>{{ error.displayedMemberName }}:</strong> {{ error.message }}
+ </li>
+ </ul>
+ </gl-collapse>
+ <gl-button
+ class="gl-text-decoration-none! gl-shadow-none! gl-mt-3"
+ data-testid="accordion-button"
+ variant="link"
+ @click="toggleErrorExpansion"
+ >
+ {{ errorCollapseText }}
+ <gl-icon
+ name="chevron-down"
+ class="gl-transition-medium"
+ :class="{ 'gl-rotate-180': isErrorsSectionExpanded }"
+ />
+ </gl-button>
+ </template>
</gl-alert>
<user-limit-notification
v-else
diff --git a/app/assets/javascripts/invite_members/components/members_token_select.vue b/app/assets/javascripts/invite_members/components/members_token_select.vue
index b2bcb9a5906..2ddb04e1eeb 100644
--- a/app/assets/javascripts/invite_members/components/members_token_select.vue
+++ b/app/assets/javascripts/invite_members/components/members_token_select.vue
@@ -1,10 +1,16 @@
<script>
import { GlTokenSelector, GlAvatar, GlAvatarLabeled, GlIcon, GlSprintf } from '@gitlab/ui';
-import { debounce } from 'lodash';
+import { debounce, isEmpty } from 'lodash';
import { __ } from '~/locale';
import { getUsers } from '~/rest_api';
import { memberName } from '../utils/member_utils';
-import { SEARCH_DELAY, USERS_FILTER_ALL, USERS_FILTER_SAML_PROVIDER_ID } from '../constants';
+import {
+ SEARCH_DELAY,
+ USERS_FILTER_ALL,
+ USERS_FILTER_SAML_PROVIDER_ID,
+ VALID_TOKEN_BACKGROUND,
+ INVALID_TOKEN_BACKGROUND,
+} from '../constants';
export default {
components: {
@@ -75,6 +81,25 @@ export default {
}
return this.$options.defaultQueryOptions;
},
+ hasInvalidMembers() {
+ return !isEmpty(this.invalidMembers);
+ },
+ },
+ watch: {
+ // We might not really want this to be *reactive* since we want the "class" state to be
+ // tied to the specific `selectedToken` such that if the token is removed and re-added, this
+ // state is reset.
+ // See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90076#note_1027165312
+ hasInvalidMembers: {
+ handler(updatedInvalidMembers) {
+ // Only update tokens if we receive invalid members
+ if (!updatedInvalidMembers) {
+ return;
+ }
+
+ this.updateTokenClasses();
+ },
+ },
},
methods: {
handleTextInput(query) {
@@ -83,6 +108,12 @@ export default {
this.loading = true;
this.retrieveUsers(query);
},
+ updateTokenClasses() {
+ this.selectedTokens = this.selectedTokens.map((token) => ({
+ ...token,
+ class: this.tokenClass(token),
+ }));
+ },
retrieveUsers: debounce(function debouncedRetrieveUsers() {
return getUsers(this.query, this.queryOptions)
.then((response) => {
@@ -98,6 +129,14 @@ export default {
this.loading = false;
});
}, SEARCH_DELAY),
+ tokenClass(token) {
+ if (this.hasError(token)) {
+ return INVALID_TOKEN_BACKGROUND;
+ }
+
+ // assume success for this token
+ return VALID_TOKEN_BACKGROUND;
+ },
handleInput() {
this.$emit('input', this.selectedTokens);
},
diff --git a/app/assets/javascripts/invite_members/components/user_limit_notification.vue b/app/assets/javascripts/invite_members/components/user_limit_notification.vue
index ae5c3c11386..6c9b1f8e6d0 100644
--- a/app/assets/javascripts/invite_members/components/user_limit_notification.vue
+++ b/app/assets/javascripts/invite_members/components/user_limit_notification.vue
@@ -10,7 +10,6 @@ import {
CLOSE_TO_LIMIT_MESSAGE,
CLOSE_TO_LIMIT_MESSAGE_PERSONAL_NAMESPACE,
DANGER_ALERT_TITLE_PERSONAL_NAMESPACE,
- WARNING_ALERT_TITLE_PERSONAL_NAMESPACE,
} from '../constants';
export default {
@@ -46,13 +45,6 @@ export default {
return this.usersLimitDataset.purchasePath;
},
warningAlertTitle() {
- if (this.usersLimitDataset.userNamespace) {
- return sprintf(WARNING_ALERT_TITLE_PERSONAL_NAMESPACE, {
- count: this.freeUsersLimit - this.membersCount,
- members: this.pluralMembers(this.freeUsersLimit - this.membersCount),
- });
- }
-
return sprintf(WARNING_ALERT_TITLE, {
count: this.freeUsersLimit - this.membersCount,
members: this.pluralMembers(this.freeUsersLimit - this.membersCount),
diff --git a/app/assets/javascripts/invite_members/constants.js b/app/assets/javascripts/invite_members/constants.js
index 6141e5e9e0b..1ceb63e2146 100644
--- a/app/assets/javascripts/invite_members/constants.js
+++ b/app/assets/javascripts/invite_members/constants.js
@@ -2,6 +2,8 @@ import { s__ } from '~/locale';
export const CLOSE_TO_LIMIT_COUNT = 2;
export const SEARCH_DELAY = 200;
+export const VALID_TOKEN_BACKGROUND = 'gl-bg-green-100';
+export const INVALID_TOKEN_BACKGROUND = 'gl-bg-red-100';
export const INVITE_MEMBERS_FOR_TASK = {
minimum_access_level: 30,
name: 'invite_members_for_task',
@@ -77,6 +79,8 @@ export const HEADER_CLOSE_LABEL = s__('InviteMembersModal|Close invite team memb
export const MEMBER_ERROR_LIST_TEXT = s__(
'InviteMembersModal|Review the invite errors and try again:',
);
+export const COLLAPSED_ERRORS = s__('InviteMembersModal|Show more (%{count})');
+export const EXPANDED_ERRORS = s__('InviteMembersModal|Show less');
export const MEMBER_MODAL_LABELS = {
modal: {
@@ -113,6 +117,8 @@ export const MEMBER_MODAL_LABELS = {
},
toastMessageSuccessful: TOAST_MESSAGE_SUCCESSFUL,
memberErrorListText: MEMBER_ERROR_LIST_TEXT,
+ collapsedErrors: COLLAPSED_ERRORS,
+ expandedErrors: EXPANDED_ERRORS,
};
export const GROUP_MODAL_LABELS = {
@@ -136,9 +142,6 @@ export const ON_SUBMIT_TRACK_LABEL = 'manage_members_clicked';
export const WARNING_ALERT_TITLE = s__(
'InviteMembersModal|You only have space for %{count} more %{members} in %{name}',
);
-export const WARNING_ALERT_TITLE_PERSONAL_NAMESPACE = s__(
- 'InviteMembersModal|You only have space for %{count} more %{members} in your personal projects',
-);
export const DANGER_ALERT_TITLE = s__(
"InviteMembersModal|You've reached your %{count} %{members} limit for %{name}",
);
@@ -153,12 +156,12 @@ export const REACHED_LIMIT_MESSAGE = s__(
export const REACHED_LIMIT_UPGRADE_SUGGESTION_MESSAGE = REACHED_LIMIT_MESSAGE.concat(
s__(
- 'InviteMembersModal| To get more members and access to additional paid features, an owner of this namespace can start a trial or upgrade to a paid tier.',
+ 'InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier.',
),
);
export const CLOSE_TO_LIMIT_MESSAGE = s__(
- 'InviteMembersModal|To get more members an owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier.',
+ 'InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier.',
);
export const CLOSE_TO_LIMIT_MESSAGE_PERSONAL_NAMESPACE = s__(
'InviteMembersModal|To make more space, you can remove members who no longer need access.',
diff --git a/app/assets/javascripts/invite_members/init_invite_members_modal.js b/app/assets/javascripts/invite_members/init_invite_members_modal.js
index a4be3f205a3..6e2c0ecb5bb 100644
--- a/app/assets/javascripts/invite_members/init_invite_members_modal.js
+++ b/app/assets/javascripts/invite_members/init_invite_members_modal.js
@@ -20,6 +20,8 @@ export default (function initInviteMembersModal() {
return false;
}
+ const usersLimitDataset = JSON.parse(el.dataset.usersLimitDataset || '{}');
+
inviteMembersModal = new Vue({
el,
name: 'InviteMembersModalRoot',
@@ -38,9 +40,10 @@ export default (function initInviteMembersModal() {
projects: JSON.parse(el.dataset.projects || '[]'),
usersFilter: el.dataset.usersFilter,
filterId: parseInt(el.dataset.filterId, 10),
- usersLimitDataset: convertObjectPropsToCamelCase(
- JSON.parse(el.dataset.usersLimitDataset || '{}'),
- ),
+ usersLimitDataset: convertObjectPropsToCamelCase({
+ ...usersLimitDataset,
+ user_namespace: parseBoolean(usersLimitDataset.user_namespace),
+ }),
},
}),
});