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:
Diffstat (limited to 'app/assets/javascripts/projects/settings/components/access_dropdown.vue')
-rw-r--r--app/assets/javascripts/projects/settings/components/access_dropdown.vue126
1 files changed, 100 insertions, 26 deletions
diff --git a/app/assets/javascripts/projects/settings/components/access_dropdown.vue b/app/assets/javascripts/projects/settings/components/access_dropdown.vue
index a2e4827cbfa..ca24e948f69 100644
--- a/app/assets/javascripts/projects/settings/components/access_dropdown.vue
+++ b/app/assets/javascripts/projects/settings/components/access_dropdown.vue
@@ -12,13 +12,14 @@ import { debounce, intersectionWith, groupBy, differenceBy, intersectionBy } fro
import { createAlert } from '~/alert';
import { __, s__, n__ } from '~/locale';
import { getUsers, getGroups, getDeployKeys } from '../api/access_dropdown_api';
-import { LEVEL_TYPES, ACCESS_LEVELS } from '../constants';
+import { LEVEL_TYPES, ACCESS_LEVELS, ACCESS_LEVEL_NONE } from '../constants';
export const i18n = {
- selectUsers: s__('ProtectedEnvironment|Select users'),
+ defaultLabel: s__('AccessDropdown|Select'),
rolesSectionHeader: s__('AccessDropdown|Roles'),
groupsSectionHeader: s__('AccessDropdown|Groups'),
usersSectionHeader: s__('AccessDropdown|Users'),
+ noRole: s__('AccessDropdown|No role'),
deployKeysSectionHeader: s__('AccessDropdown|Deploy Keys'),
ownedBy: __('Owned by %{image_tag}'),
};
@@ -51,7 +52,7 @@ export default {
label: {
type: String,
required: false,
- default: i18n.selectUsers,
+ default: i18n.defaultLabel,
},
disabled: {
type: Boolean,
@@ -68,6 +69,31 @@ export default {
required: false,
default: () => [],
},
+ toggleClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ searchEnabled: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ block: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ testId: {
+ type: String,
+ required: false,
+ default: undefined,
+ },
+ showUsers: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
data() {
return {
@@ -96,6 +122,9 @@ export default {
this.deployKeys.length
);
},
+ isAccessesLevelNoneSelected() {
+ return this.selected.role[0].id === ACCESS_LEVEL_NONE;
+ },
toggleLabel() {
const counts = Object.entries(this.selected).reduce((acc, [key, value]) => {
acc[key] = value.length;
@@ -115,7 +144,11 @@ export default {
const labelPieces = [];
if (counts[LEVEL_TYPES.ROLE] > 0) {
- labelPieces.push(n__('1 role', '%d roles', counts[LEVEL_TYPES.ROLE]));
+ if (this.isAccessesLevelNoneSelected) {
+ labelPieces.push(this.$options.i18n.noRole);
+ } else {
+ labelPieces.push(n__('1 role', '%d roles', counts[LEVEL_TYPES.ROLE]));
+ }
}
if (counts[LEVEL_TYPES.USER] > 0) {
@@ -132,8 +165,14 @@ export default {
return labelPieces.join(', ') || this.label;
},
- toggleClass() {
- return this.toggleLabel === this.label ? 'gl-text-gray-500!' : '';
+ fossWithMergeAccess() {
+ return !this.hasLicense && this.accessLevel === ACCESS_LEVELS.MERGE;
+ },
+ dropdownToggleClass() {
+ return {
+ 'gl-text-gray-500!': this.toggleLabel === this.label,
+ [this.toggleClass]: true,
+ };
},
selection() {
return [
@@ -180,7 +219,7 @@ export default {
);
},
focusInput() {
- this.$refs.search.focusInput();
+ this.$refs.search?.focusInput();
},
getData({ initial = false } = {}) {
this.initialLoading = initial;
@@ -190,10 +229,10 @@ export default {
Promise.all([
getDeployKeys(this.query),
getUsers(this.query),
- this.groups.length ? Promise.resolve({ data: this.groups }) : getGroups(),
+ this.groups.length ? Promise.resolve(this.groups) : getGroups(),
])
.then(([deployKeysResponse, usersResponse, groupsResponse]) => {
- this.consolidateData(deployKeysResponse.data, usersResponse.data, groupsResponse.data);
+ this.consolidateData(deployKeysResponse.data, usersResponse.data, groupsResponse);
this.setSelected({ initial });
})
.catch(() =>
@@ -224,13 +263,18 @@ export default {
if (this.hasLicense) {
this.groups = groupsResponse.map((group) => ({ ...group, type: LEVEL_TYPES.GROUP }));
- this.users = usersResponse.map(({ id, name, username, avatar_url }) => ({
- id,
- name,
- username,
- avatar_url,
- type: LEVEL_TYPES.USER,
- }));
+
+ // Has to be checked against server response
+ // because the selected item can be in filter results
+ if (this.showUsers) {
+ this.users = usersResponse.map(({ id, name, username, avatar_url }) => ({
+ id,
+ name,
+ username,
+ avatar_url,
+ type: LEVEL_TYPES.USER,
+ }));
+ }
}
this.deployKeys = deployKeysResponse.map((response) => {
@@ -328,14 +372,38 @@ export default {
return [...added, ...removed, ...preserved];
},
onItemClick(item) {
- this.toggleSelection(this.selected[item.type], item);
+ this.toggleSelection(item);
this.emitUpdate();
},
- toggleSelection(arr, item) {
- const itemIndex = arr.findIndex(({ id }) => id === item.id);
- if (itemIndex > -1) {
- arr.splice(itemIndex, 1);
- } else arr.push(item);
+ toggleSelection(item) {
+ if (item.id === ACCESS_LEVEL_NONE) {
+ this.selected[LEVEL_TYPES.ROLE] = [item];
+ return;
+ }
+
+ const itemSelected = this.isSelected(item);
+ if (itemSelected) {
+ this.selected[item.type] = this.selected[item.type].filter(({ id }) => id !== item.id);
+ return;
+ }
+
+ // We're not multiselecting quite yet in "Merge" access dropdown, on FOSS:
+ // remove all preselected items before selecting this item
+ // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37499
+ if (this.fossWithMergeAccess) this.clearSelection();
+ else if (item.type === LEVEL_TYPES.ROLE) this.unselectNone();
+
+ this.selected[item.type].push(item);
+ },
+ unselectNone() {
+ this.selected[LEVEL_TYPES.ROLE] = this.selected[LEVEL_TYPES.ROLE].filter(
+ ({ id }) => id !== ACCESS_LEVEL_NONE,
+ );
+ },
+ clearSelection() {
+ Object.values(LEVEL_TYPES).forEach((level) => {
+ this.selected[level] = [];
+ });
},
isSelected(item) {
return this.selected[item.type].some((selected) => selected.id === item.id);
@@ -346,6 +414,10 @@ export default {
onHide() {
this.$emit('hidden', this.selection);
},
+ onShown() {
+ this.$emit('shown');
+ this.focusInput();
+ },
},
};
</script>
@@ -354,13 +426,15 @@ export default {
<gl-dropdown
:disabled="disabled || initialLoading"
:text="toggleLabel"
- class="gl-min-w-20"
- :toggle-class="toggleClass"
+ :block="block"
+ class="gl-min-w-20 gl-p-0!"
+ :toggle-class="dropdownToggleClass"
aria-labelledby="allowed-users-label"
- @shown="focusInput"
+ :data-testid="testId"
+ @shown="onShown"
@hidden="onHide"
>
- <template #header>
+ <template v-if="searchEnabled" #header>
<gl-search-box-by-type ref="search" v-model.trim="query" :is-loading="loading" />
</template>
<template v-if="roles.length">