Commit 6bf9c407 authored by Clement Ho's avatar Clement Ho

Merge branch 'winh-protection-push-dropdowns' into 'master'

Shorten protected branch / tag access level dropdown text

Closes #5216

See merge request gitlab-org/gitlab-ee!5091
parents c79679f6 9c38fec6
......@@ -935,11 +935,6 @@ pre.light-well {
}
}
.dropdown-menu-toggle {
width: 100%;
max-width: 300px;
}
.flash-container {
padding: 0;
}
......
.panel.panel-default.protected-branches-list.js-protected-branches-list
.protected-branches-list.js-protected-branches-list
- if @protected_branches.empty?
.panel-heading
%h3.panel-title
......
.panel.panel-default.protected-tags-list.js-protected-tags-list
.protected-tags-list.js-protected-tags-list
- if @protected_tags.empty?
.panel-heading
%h3.panel-title
......
/* eslint-disable no-underscore-dangle, class-methods-use-this */
import $ from 'jquery';
import _ from 'underscore';
import axios from '~/lib/utils/axios_utils';
import Flash from '~/flash';
import { n__ } from '~/locale';
import { LEVEL_TYPES, LEVEL_ID_PROP, ACCESS_LEVEL_NONE } from './constants';
export default class ProtectedBranchAccessDropdown {
export default class AccessDropdown {
constructor(options) {
const {
$dropdown,
accessLevel,
accessLevelsData,
} = options;
const { $dropdown, accessLevel, accessLevelsData } = options;
this.options = options;
this.groups = [];
this.accessLevel = accessLevel;
this.accessLevelsData = accessLevelsData.roles;
this.$dropdown = $dropdown;
this.$wrap = this.$dropdown.closest(`.${this.accessLevel}-container`);
this.$protectedTagsContainer = $('.js-protected-branches-container');
this.usersPath = '/autocomplete/users.json';
this.groupsPath = '/autocomplete/project_groups.json';
this.defaultLabel = this.$dropdown.data('defaultLabel');
......@@ -47,7 +42,7 @@ export default class ProtectedBranchAccessDropdown {
onHide();
}
},
clicked: (options) => {
clicked: options => {
const { $el, e } = options;
const item = options.selectedObj;
......@@ -56,7 +51,7 @@ export default class ProtectedBranchAccessDropdown {
if ($el.is('.is-active')) {
if (item.id === this.noOneObj.id) {
// remove all others selected items
this.accessLevelsData.forEach((level) => {
this.accessLevelsData.forEach(level => {
if (level.id !== item.id) {
this.removeSelectedItem(level);
}
......@@ -65,7 +60,9 @@ export default class ProtectedBranchAccessDropdown {
// remove selected item visually
this.$wrap.find(`.item-${item.type}`).removeClass('is-active');
} else {
const $noOne = this.$wrap.find(`.is-active.item-${item.type}[data-role-id="${this.noOneObj.id}"]`);
const $noOne = this.$wrap.find(
`.is-active.item-${item.type}[data-role-id="${this.noOneObj.id}"]`,
);
if ($noOne.length) {
$noOne.removeClass('is-active');
this.removeSelectedItem(this.noOneObj);
......@@ -86,6 +83,8 @@ export default class ProtectedBranchAccessDropdown {
}
},
});
this.$dropdown.find('.dropdown-toggle-text').text(this.toggleLabel());
}
persistPreselectedItems() {
......@@ -95,7 +94,7 @@ export default class ProtectedBranchAccessDropdown {
return;
}
const persistedItems = itemsToPreselect.map((item) => {
const persistedItems = itemsToPreselect.map(item => {
const persistedItem = Object.assign({}, item);
persistedItem.persisted = true;
return persistedItem;
......@@ -120,7 +119,7 @@ export default class ProtectedBranchAccessDropdown {
getInputData() {
const selectedItems = this.getAllSelectedItems();
const accessLevels = selectedItems.map((item) => {
const accessLevels = selectedItems.map(item => {
const obj = {};
if (typeof item.id !== 'undefined') {
......@@ -222,14 +221,11 @@ export default class ProtectedBranchAccessDropdown {
return true;
}
if (item.type === LEVEL_TYPES.USER &&
item.user_id === itemToDelete.id) {
if (item.type === LEVEL_TYPES.USER && item.user_id === itemToDelete.id) {
index = i;
} else if (item.type === LEVEL_TYPES.ROLE &&
item.access_level === itemToDelete.id) {
} else if (item.type === LEVEL_TYPES.ROLE && item.access_level === itemToDelete.id) {
index = i;
} else if (item.type === LEVEL_TYPES.GROUP &&
item.group_id === itemToDelete.id) {
} else if (item.type === LEVEL_TYPES.GROUP && item.group_id === itemToDelete.id) {
index = i;
}
......@@ -256,34 +252,48 @@ export default class ProtectedBranchAccessDropdown {
toggleLabel() {
const currentItems = this.getSelectedItems();
const types = _.groupBy(currentItems, item => item.type);
let label = [];
const $dropdownToggleText = this.$dropdown.find('.dropdown-toggle-text');
if (currentItems.length) {
label = Object.keys(LEVEL_TYPES).map((levelType) => {
const typeName = LEVEL_TYPES[levelType];
const numberOfTypes = types[typeName] ? types[typeName].length : 0;
const text = numberOfTypes === 1 ? typeName : `${typeName}s`;
if (currentItems.length === 0) {
$dropdownToggleText.addClass('is-default');
return this.defaultLabel;
}
return `${numberOfTypes} ${text}`;
});
} else {
label.push(this.defaultLabel);
$dropdownToggleText.removeClass('is-default');
if (currentItems.length === 1 && currentItems[0].type === LEVEL_TYPES.ROLE) {
const roleData = this.accessLevelsData.find(data => data.id === currentItems[0].access_level);
return roleData.text;
}
const labelPieces = [];
const counts = _.countBy(currentItems, item => item.type);
if (counts[LEVEL_TYPES.ROLE] > 0) {
labelPieces.push(n__('1 role', '%d roles', counts[LEVEL_TYPES.ROLE]));
}
this.$dropdown.find('.dropdown-toggle-text').toggleClass('is-default', !currentItems.length);
if (counts[LEVEL_TYPES.USER] > 0) {
labelPieces.push(n__('1 user', '%d users', counts[LEVEL_TYPES.USER]));
}
if (counts[LEVEL_TYPES.GROUP] > 0) {
labelPieces.push(n__('1 group', '%d groups', counts[LEVEL_TYPES.GROUP]));
}
return label.join(', ');
return labelPieces.join(', ');
}
getData(query, callback) {
Promise.all([
this.getUsers(query),
this.groupsData ? Promise.resolve(this.groupsData) : this.getGroups(),
]).then(([usersResponse, groupsResponse]) => {
this.groupsData = groupsResponse;
callback(this.consolidateData(usersResponse.data, groupsResponse.data));
}).catch(() => Flash('Failed to load groups & users.'));
])
.then(([usersResponse, groupsResponse]) => {
this.groupsData = groupsResponse;
callback(this.consolidateData(usersResponse.data, groupsResponse.data));
})
.catch(() => Flash('Failed to load groups & users.'));
}
consolidateData(usersResponse, groupsResponse) {
......@@ -308,12 +318,15 @@ export default class ProtectedBranchAccessDropdown {
/*
* Build groups
*/
const groups = groupsResponse.map(group => ({ ...group, type: LEVEL_TYPES.GROUP }));
const groups = groupsResponse.map(group => ({
...group,
type: LEVEL_TYPES.GROUP,
}));
/*
* Build roles
*/
const roles = this.accessLevelsData.map((level) => {
const roles = this.accessLevelsData.map(level => {
/* eslint-disable no-param-reassign */
// This re-assignment is intentional as
// level.type property is being used in removeSelectedItem()
......@@ -327,7 +340,7 @@ export default class ProtectedBranchAccessDropdown {
/*
* Build users
*/
const users = selectedItems.filter(item => item.type === LEVEL_TYPES.USER).map((item) => {
const users = selectedItems.filter(item => item.type === LEVEL_TYPES.USER).map(item => {
// Save identifiers for easy-checking more later
map.push(LEVEL_TYPES.USER + item.user_id);
......@@ -342,7 +355,7 @@ export default class ProtectedBranchAccessDropdown {
// Has to be checked against server response
// because the selected item can be in filter results
usersResponse.forEach((response) => {
usersResponse.forEach(response => {
// Add is it has not been added
if (map.indexOf(LEVEL_TYPES.USER + response.id) === -1) {
const user = Object.assign({}, response);
......@@ -454,7 +467,9 @@ export default class ProtectedBranchAccessDropdown {
groupRowHtml(group, isActive) {
const isActiveClass = isActive || '';
const avatarEl = group.avatar_url ? `<img src="${group.avatar_url}" class="avatar avatar-inline" width="30">` : '';
const avatarEl = group.avatar_url
? `<img src="${group.avatar_url}" class="avatar avatar-inline" width="30">`
: '';
return `
<li>
......
export const LEVEL_TYPES = {
ROLE: 'role',
USER: 'user',
GROUP: 'group',
};
export const LEVEL_ID_PROP = {
ROLE: 'access_level',
USER: 'user_id',
GROUP: 'group_id',
};
export const ACCESS_LEVEL_NONE = 0;
......@@ -3,8 +3,8 @@ import axios from '~/lib/utils/axios_utils';
import AccessorUtilities from '~/lib/utils/accessor';
import Flash from '~/flash';
import CreateItemDropdown from '~/create_item_dropdown';
import AccessDropdown from 'ee/projects/settings/access_dropdown';
import { ACCESS_LEVELS, LEVEL_TYPES } from './constants';
import ProtectedBranchAccessDropdown from './protected_branch_access_dropdown';
const PB_LOCAL_STORAGE_KEY = 'protected-branches-defaults';
......@@ -30,7 +30,7 @@ export default class ProtectedBranchCreate {
this.onSelectCallback = this.onSelect.bind(this);
// Allowed to Merge dropdown
this[`${ACCESS_LEVELS.MERGE}_dropdown`] = new ProtectedBranchAccessDropdown({
this[`${ACCESS_LEVELS.MERGE}_dropdown`] = new AccessDropdown({
$dropdown: $allowedToMergeDropdown,
accessLevelsData: gon.merge_access_levels,
onSelect: this.onSelectCallback,
......@@ -38,7 +38,7 @@ export default class ProtectedBranchCreate {
});
// Allowed to Push dropdown
this[`${ACCESS_LEVELS.PUSH}_dropdown`] = new ProtectedBranchAccessDropdown({
this[`${ACCESS_LEVELS.PUSH}_dropdown`] = new AccessDropdown({
$dropdown: $allowedToPushDropdown,
accessLevelsData: gon.push_access_levels,
onSelect: this.onSelectCallback,
......@@ -82,12 +82,12 @@ export default class ProtectedBranchCreate {
},
};
Object.keys(ACCESS_LEVELS).forEach((level) => {
Object.keys(ACCESS_LEVELS).forEach(level => {
const accessLevel = ACCESS_LEVELS[level];
const selectedItems = this[`${accessLevel}_dropdown`].getSelectedItems();
const levelAttributes = [];
selectedItems.forEach((item) => {
selectedItems.forEach(item => {
if (item.type === LEVEL_TYPES.USER) {
levelAttributes.push({
user_id: item.user_id,
......@@ -115,10 +115,14 @@ export default class ProtectedBranchCreate {
if (savedDefaults != null) {
this[`${ACCESS_LEVELS.MERGE}_dropdown`].setSelectedItems(savedDefaults.merge);
let updatedLabel = this[`${ACCESS_LEVELS.MERGE}_dropdown`].toggleLabel();
this[`${ACCESS_LEVELS.MERGE}_dropdown`].$dropdown.find('.dropdown-toggle-text').text(updatedLabel);
this[`${ACCESS_LEVELS.MERGE}_dropdown`].$dropdown
.find('.dropdown-toggle-text')
.text(updatedLabel);
this[`${ACCESS_LEVELS.PUSH}_dropdown`].setSelectedItems(savedDefaults.push);
updatedLabel = this[`${ACCESS_LEVELS.PUSH}_dropdown`].toggleLabel();
this[`${ACCESS_LEVELS.PUSH}_dropdown`].$dropdown.find('.dropdown-toggle-text').text(updatedLabel);
this[`${ACCESS_LEVELS.PUSH}_dropdown`].$dropdown
.find('.dropdown-toggle-text')
.text(updatedLabel);
}
}
}
......
......@@ -4,8 +4,8 @@ import $ from 'jquery';
import _ from 'underscore';
import axios from '~/lib/utils/axios_utils';
import Flash from '~/flash';
import AccessDropdown from 'ee/projects/settings/access_dropdown';
import { ACCESS_LEVELS, LEVEL_TYPES } from './constants';
import ProtectedBranchAccessDropdown from './protected_branch_access_dropdown';
export default class ProtectedBranchEdit {
constructor(options) {
......@@ -15,15 +15,19 @@ export default class ProtectedBranchEdit {
this.$allowedToMergeDropdown = this.$wrap.find('.js-allowed-to-merge');
this.$allowedToPushDropdown = this.$wrap.find('.js-allowed-to-push');
this.$wraps[ACCESS_LEVELS.MERGE] = this.$allowedToMergeDropdown.closest(`.${ACCESS_LEVELS.MERGE}-container`);
this.$wraps[ACCESS_LEVELS.PUSH] = this.$allowedToPushDropdown.closest(`.${ACCESS_LEVELS.PUSH}-container`);
this.$wraps[ACCESS_LEVELS.MERGE] = this.$allowedToMergeDropdown.closest(
`.${ACCESS_LEVELS.MERGE}-container`,
);
this.$wraps[ACCESS_LEVELS.PUSH] = this.$allowedToPushDropdown.closest(
`.${ACCESS_LEVELS.PUSH}-container`,
);
this.buildDropdowns();
}
buildDropdowns() {
// Allowed to merge dropdown
this[`${ACCESS_LEVELS.MERGE}_dropdown`] = new ProtectedBranchAccessDropdown({
this[`${ACCESS_LEVELS.MERGE}_dropdown`] = new AccessDropdown({
accessLevel: ACCESS_LEVELS.MERGE,
accessLevelsData: gon.merge_access_levels,
$dropdown: this.$allowedToMergeDropdown,
......@@ -32,7 +36,7 @@ export default class ProtectedBranchEdit {
});
// Allowed to push dropdown
this[`${ACCESS_LEVELS.PUSH}_dropdown`] = new ProtectedBranchAccessDropdown({
this[`${ACCESS_LEVELS.PUSH}_dropdown`] = new AccessDropdown({
accessLevel: ACCESS_LEVELS.PUSH,
accessLevelsData: gon.push_access_levels,
$dropdown: this.$allowedToPushDropdown,
......@@ -64,33 +68,38 @@ export default class ProtectedBranchEdit {
return acc;
}, {});
axios.patch(this.$wrap.data('url'), {
protected_branch: formData,
}).then(({ data }) => {
this.hasChanges = false;
Object.keys(ACCESS_LEVELS).forEach((level) => {
const accessLevelName = ACCESS_LEVELS[level];
// The data coming from server will be the new persisted *state* for each dropdown
this.setSelectedItemsToDropdown(data[accessLevelName], `${accessLevelName}_dropdown`);
axios
.patch(this.$wrap.data('url'), {
protected_branch: formData,
})
.then(({ data }) => {
this.hasChanges = false;
Object.keys(ACCESS_LEVELS).forEach(level => {
const accessLevelName = ACCESS_LEVELS[level];
// The data coming from server will be the new persisted *state* for each dropdown
this.setSelectedItemsToDropdown(data[accessLevelName], `${accessLevelName}_dropdown`);
});
this.$allowedToMergeDropdown.enable();
this.$allowedToPushDropdown.enable();
})
.catch(() => {
this.$allowedToMergeDropdown.enable();
this.$allowedToPushDropdown.enable();
Flash('Failed to update branch!', null, $('.js-protected-branches-list'));
});
this.$allowedToMergeDropdown.enable();
this.$allowedToPushDropdown.enable();
}).catch(() => {
this.$allowedToMergeDropdown.enable();
this.$allowedToPushDropdown.enable();
Flash('Failed to update branch!', null, $('.js-protected-branches-list'));
});
}
setSelectedItemsToDropdown(items = [], dropdownName) {
const itemsToAdd = items.map((currentItem) => {
const itemsToAdd = items.map(currentItem => {
if (currentItem.user_id) {
// Do this only for users for now
// get the current data for selected items
const selectedItems = this[dropdownName].getSelectedItems();
const currentSelectedItem = _.findWhere(selectedItems, { user_id: currentItem.user_id });
const currentSelectedItem = _.findWhere(selectedItems, {
user_id: currentItem.user_id,
});
return {
id: currentItem.id,
......
import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import Flash from '~/flash';
import createFlash from '~/flash';
import CreateItemDropdown from '~/create_item_dropdown';
import { s__ } from '~/locale';
import AccessDropdown from 'ee/projects/settings/access_dropdown';
import { ACCESS_LEVELS, LEVEL_TYPES } from './constants';
import ProtectedTagAccessDropdown from './protected_tag_access_dropdown';
export default class ProtectedTagCreate {
constructor() {
......@@ -24,7 +25,7 @@ export default class ProtectedTagCreate {
this.onSelectCallback = this.onSelect.bind(this);
// Allowed to Create dropdown
this[`${ACCESS_LEVELS.CREATE}_dropdown`] = new ProtectedTagAccessDropdown({
this[`${ACCESS_LEVELS.CREATE}_dropdown`] = new AccessDropdown({
$dropdown: $allowedToCreateDropdown,
accessLevelsData: gon.create_access_levels,
onSelect: this.onSelectCallback,
......@@ -44,7 +45,9 @@ export default class ProtectedTagCreate {
// Enable submit button after selecting an option
onSelect() {
const $allowedToCreate = this[`${ACCESS_LEVELS.CREATE}_dropdown`].getSelectedItems();
const toggle = !(this.$form.find('input[name="protected_tag[name]"]').val() && $allowedToCreate.length);
const toggle = !(
this.$form.find('input[name="protected_tag[name]"]').val() && $allowedToCreate.length
);
this.$form.find('input[type="submit"]').attr('disabled', toggle);
}
......@@ -61,12 +64,12 @@ export default class ProtectedTagCreate {
},
};
Object.keys(ACCESS_LEVELS).forEach((level) => {
Object.keys(ACCESS_LEVELS).forEach(level => {
const accessLevel = ACCESS_LEVELS[level];
const selectedItems = this[`${ACCESS_LEVELS.CREATE}_dropdown`].getSelectedItems();
const levelAttributes = [];
selectedItems.forEach((item) => {
selectedItems.forEach(item => {
if (item.type === LEVEL_TYPES.USER) {
levelAttributes.push({
user_id: item.user_id,
......@@ -94,6 +97,7 @@ export default class ProtectedTagCreate {
axios[this.$form.attr('method')](this.$form.attr('action'), this.getFormData())
.then(() => {
location.reload();
}).catch(() => Flash('Failed to protect the tag'));
})
.catch(() => createFlash(s__('ProjectSettings|Failed to protect the tag')));
}
}
......@@ -3,9 +3,10 @@
import $ from 'jquery';
import _ from 'underscore';
import axios from '~/lib/utils/axios_utils';
import Flash from '~/flash';
import createFlash from '~/flash';
import { s__ } from '~/locale';
import AccessDropdown from 'ee/projects/settings/access_dropdown';
import { ACCESS_LEVELS, LEVEL_TYPES } from './constants';
import ProtectedTagAccessDropdown from './protected_tag_access_dropdown';
export default class ProtectedTagEdit {
constructor(options) {
......@@ -13,14 +14,16 @@ export default class ProtectedTagEdit {
this.$wrap = options.$wrap;
this.$allowedToCreateDropdownButton = this.$wrap.find('.js-allowed-to-create');
this.$allowedToCreateDropdownContainer = this.$allowedToCreateDropdownButton.closest('.create_access_levels-container');
this.$allowedToCreateDropdownContainer = this.$allowedToCreateDropdownButton.closest(
'.create_access_levels-container',
);
this.buildDropdowns();
}
buildDropdowns() {
// Allowed to create dropdown
this[`${ACCESS_LEVELS.CREATE}_dropdown`] = new ProtectedTagAccessDropdown({
this[`${ACCESS_LEVELS.CREATE}_dropdown`] = new AccessDropdown({
accessLevel: ACCESS_LEVELS.CREATE,
accessLevelsData: gon.create_access_levels,
$dropdown: this.$allowedToCreateDropdownButton,
......@@ -52,30 +55,35 @@ export default class ProtectedTagEdit {
return acc;
}, {});
axios.patch(this.$wrap.data('url'), {
protected_tag: formData,
}).then(({ data }) => {
this.hasChanges = false;
Object.keys(ACCESS_LEVELS).forEach((level) => {
const accessLevelName = ACCESS_LEVELS[level];
// The data coming from server will be the new persisted *state* for each dropdown
this.setSelectedItemsToDropdown(data[accessLevelName], `${accessLevelName}_dropdown`);
axios
.patch(this.$wrap.data('url'), {
protected_tag: formData,
})
.then(({ data }) => {
this.hasChanges = false;
Object.keys(ACCESS_LEVELS).forEach(level => {
const accessLevelName = ACCESS_LEVELS[level];
// The data coming from server will be the new persisted *state* for each dropdown
this.setSelectedItemsToDropdown(data[accessLevelName], `${accessLevelName}_dropdown`);
});
})
.catch(() => {
$.scrollTo(0);
createFlash(s__('ProjectSettings|Failed to update tag!'));
});
}).catch(() => {
$.scrollTo(0);
Flash('Failed to update tag!');
});
}
setSelectedItemsToDropdown(items = [], dropdownName) {
const itemsToAdd = items.map((currentItem) => {
const itemsToAdd = items.map(currentItem => {
if (currentItem.user_id) {
// Do this only for users for now
// get the current data for selected items
const selectedItems = this[dropdownName].getSelectedItems();
const currentSelectedItem = _.findWhere(selectedItems, { user_id: currentItem.user_id });
const currentSelectedItem = _.findWhere(selectedItems, {
user_id: currentItem.user_id,
});
return {
id: currentItem.id,
......
- default_label = 'Select'
- dropdown_label = default_label
%div{ class: "#{input_basic_name}-container" }
- if access_levels.present?
- dropdown_label = [pluralize(level_frequencies[:role], 'role'), pluralize(level_frequencies[:user], 'user'), pluralize(level_frequencies[:group], 'group')].to_sentence
= dropdown_tag(dropdown_label, options: { toggle_class: "#{toggle_class} js-multiselect", dropdown_class: 'dropdown-menu-user dropdown-menu-selectable', filter: true,
data: { default_label: default_label, preselected_items: access_levels_data(access_levels) } })
%td
= render partial: 'projects/protected_branches/ee/access_level_dropdown', locals: { protected_branch: protected_branch, access_levels: protected_branch.merge_access_levels, level_frequencies: access_level_frequencies(protected_branch.merge_access_levels), input_basic_name: 'merge_access_levels', toggle_class: 'js-allowed-to-merge' }
= render partial: 'projects/settings/ee/access_level_dropdown', locals: { protected_branch: protected_branch, access_levels: protected_branch.merge_access_levels, level_frequencies: access_level_frequencies(protected_branch.merge_access_levels), input_basic_name: 'merge_access_levels', toggle_class: 'js-allowed-to-merge' }
%td
= render partial: 'projects/protected_branches/ee/access_level_dropdown', locals: { protected_branch: protected_branch, access_levels: protected_branch.push_access_levels, level_frequencies: access_level_frequencies(protected_branch.push_access_levels), input_basic_name: 'push_access_levels', toggle_class: 'js-allowed-to-push' }
= render partial: 'projects/settings/ee/access_level_dropdown', locals: { protected_branch: protected_branch, access_levels: protected_branch.push_access_levels, level_frequencies: access_level_frequencies(protected_branch.push_access_levels), input_basic_name: 'push_access_levels', toggle_class: 'js-allowed-to-push' }
- default_label = 'Select'
- dropdown_label = default_label
%div{ class: "#{input_basic_name}-container" }
- if access_levels.present?
- dropdown_label = [pluralize(level_frequencies[:role], 'role'), pluralize(level_frequencies[:user], 'user'), pluralize(level_frequencies[:group], 'group')].to_sentence
= dropdown_tag(dropdown_label, options: { toggle_class: "#{toggle_class} js-multiselect", dropdown_class: 'dropdown-menu-user dropdown-menu-selectable', filter: true,
data: { default_label: default_label, preselected_items: access_levels_data(access_levels) } })
%td
= render partial: 'projects/protected_tags/ee/access_level_dropdown', locals: { protected_tag: protected_tag, access_levels: protected_tag.create_access_levels, level_frequencies: access_level_frequencies(protected_tag.create_access_levels), input_basic_name: 'create_access_levels', toggle_class: 'js-allowed-to-create' }
= render partial: 'projects/settings/ee/access_level_dropdown', locals: { protected_tag: protected_tag, access_levels: protected_tag.create_access_levels, level_frequencies: access_level_frequencies(protected_tag.create_access_levels), input_basic_name: 'create_access_levels', toggle_class: 'js-allowed-to-create' }
- default_label = s_('RepositorySettingsAccessLevel|Select')
%div{ class: "#{input_basic_name}-container" }
= dropdown_tag(default_label, options: { toggle_class: "#{toggle_class} js-multiselect", dropdown_class: 'dropdown-menu-user dropdown-menu-selectable', filter: true, data: { default_label: default_label, preselected_items: access_levels_data(access_levels) } })
---
title: Shorten protected branch / tag access level dropdown text
merge_request: 5091
author:
type: changed
......@@ -5,7 +5,9 @@ module EE
find(".js-allowed-to-#{operation}").click
wait_for_requests
Array(option).each { |opt| click_on(opt) }
within('.dropdown-content') do
Array(option).each { |opt| click_on(opt) }
end
find(".js-allowed-to-#{operation}").click # needed to submit form in some cases
end
......
......@@ -84,10 +84,10 @@ feature 'Protected Branches', :js do
within form do
page.within(".js-allowed-to-merge") do
expect(page.find(".dropdown-toggle-text")).to have_content("1 role, 0 users, 0 groups")
expect(page.find(".dropdown-toggle-text")).to have_content("No one")
end
page.within(".js-allowed-to-push") do
expect(page.find(".dropdown-toggle-text")).to have_content("1 role, 0 users, 0 groups")
expect(page.find(".dropdown-toggle-text")).to have_content("Developers + Masters")
end
end
end
......
......@@ -13,7 +13,9 @@ feature 'Protected Tags', :js do
find(".js-allowed-to-#{operation}").click
wait_for_requests
Array(option).each { |opt| click_on(opt) }
within('.dropdown-content') do
Array(option).each { |opt| click_on(opt) }
end
find(".js-allowed-to-#{operation}").click # needed to submit form in some cases
end
......
import $ from 'jquery';
import AccessDropdown from 'ee/projects/settings/access_dropdown';
import { LEVEL_TYPES } from 'ee/projects/settings/constants';
describe('AccessDropdown', () => {
const defaultLabel = 'dummy default label';
let dropdown;
beforeEach(() => {
setFixtures(`
<div id="dummy-dropdown">
<span class="dropdown-toggle-text"></span>
</div>
`);
const $dropdown = $('#dummy-dropdown');
$dropdown.data('defaultLabel', defaultLabel);
const options = {
$dropdown,
accessLevelsData: {
roles: [
{
id: 42,
text: 'Dummy Role',
},
],
},
};
dropdown = new AccessDropdown(options);
});
describe('toggleLabel', () => {
let $dropdownToggleText;
const dummyItems = [
{ type: LEVEL_TYPES.ROLE, access_level: 42 },
{ type: LEVEL_TYPES.USER },
{ type: LEVEL_TYPES.USER },
{ type: LEVEL_TYPES.GROUP },
{ type: LEVEL_TYPES.GROUP },
{ type: LEVEL_TYPES.GROUP },
];
beforeEach(() => {
$dropdownToggleText = $('.dropdown-toggle-text');
});
it('displays number of items', () => {
dropdown.setSelectedItems(dummyItems);
$dropdownToggleText.addClass('is-default');
const label = dropdown.toggleLabel();
expect(label).toBe('1 role, 2 users, 3 groups');
expect($dropdownToggleText).not.toHaveClass('is-default');
});
describe('without selected items', () => {
beforeEach(() => {
dropdown.setSelectedItems([]);
});
it('falls back to default label', () => {
const label = dropdown.toggleLabel();
expect(label).toBe(defaultLabel);
expect($dropdownToggleText).toHaveClass('is-default');
});
});
describe('with only role', () => {
beforeEach(() => {
dropdown.setSelectedItems(dummyItems.filter(item => item.type === LEVEL_TYPES.ROLE));
$dropdownToggleText.addClass('is-default');
});
it('displays the role name', () => {
const label = dropdown.toggleLabel();
expect(label).toBe('Dummy Role');
expect($dropdownToggleText).not.toHaveClass('is-default');
});
});
describe('with only users', () => {
beforeEach(() => {
dropdown.setSelectedItems(dummyItems.filter(item => item.type === LEVEL_TYPES.USER));
$dropdownToggleText.addClass('is-default');
});
it('displays number of users', () => {
const label = dropdown.toggleLabel();
expect(label).toBe('2 users');
expect($dropdownToggleText).not.toHaveClass('is-default');
});
});
describe('with only groups', () => {
beforeEach(() => {
dropdown.setSelectedItems(dummyItems.filter(item => item.type === LEVEL_TYPES.GROUP));
$dropdownToggleText.addClass('is-default');
});
it('displays number of groups', () => {
const label = dropdown.toggleLabel();
expect(label).toBe('3 groups');
expect($dropdownToggleText).not.toHaveClass('is-default');
});
});
describe('with users and groups', () => {
beforeEach(() => {
const selectedTypes = [LEVEL_TYPES.GROUP, LEVEL_TYPES.USER];
dropdown.setSelectedItems(dummyItems.filter(item => selectedTypes.includes(item.type)));
$dropdownToggleText.addClass('is-default');
});
it('displays number of groups', () => {
const label = dropdown.toggleLabel();
expect(label).toBe('2 users, 3 groups');
expect($dropdownToggleText).not.toHaveClass('is-default');
});
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment