Commit c9c75dec authored by Tim Zallmann's avatar Tim Zallmann Committed by Kushal Pandya

On-demand loading of select2

Fix for loading select2 on demand

Fix of general select2 setup + linting fixes

Typo in exclude for stylelint
Added lazy CSS Loading for all Select2 instances

Fixed Spec around Select 2 + no-nesting  rules
parent ce9924ad
import $ from 'jquery'; import $ from 'jquery';
import { loadCSSFile } from '../lib/utils/css_utils';
export default () => { export default () => {
if ($('select.select2').length) { const $select2Elements = $('select.select2');
if ($select2Elements.length) {
import(/* webpackChunkName: 'select2' */ 'select2/select2') import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => { .then(() => {
$('select.select2').select2({ // eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => {
$select2Elements.select2({
width: 'resolve', width: 'resolve',
minimumResultsForSearch: 10, minimumResultsForSearch: 10,
dropdownAutoWidth: true, dropdownAutoWidth: true,
...@@ -12,11 +17,13 @@ export default () => { ...@@ -12,11 +17,13 @@ export default () => {
// Close select2 on escape // Close select2 on escape
$('.js-select2').on('select2-close', () => { $('.js-select2').on('select2-close', () => {
setTimeout(() => { requestAnimationFrame(() => {
$('.select2-container-active').removeClass('select2-container-active'); $('.select2-container-active').removeClass('select2-container-active');
$(':focus').blur(); $(':focus').blur();
}, 1);
}); });
});
})
.catch(() => {});
}) })
.catch(() => {}); .catch(() => {});
} }
......
...@@ -4,10 +4,35 @@ import axios from './lib/utils/axios_utils'; ...@@ -4,10 +4,35 @@ import axios from './lib/utils/axios_utils';
import Api from './api'; import Api from './api';
import { normalizeHeaders } from './lib/utils/common_utils'; import { normalizeHeaders } from './lib/utils/common_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { loadCSSFile } from './lib/utils/css_utils';
const fetchGroups = params => {
axios[params.type.toLowerCase()](params.url, {
params: params.data,
})
.then(res => {
const results = res.data || [];
const headers = normalizeHeaders(res.headers);
const currentPage = parseInt(headers['X-PAGE'], 10) || 0;
const totalPages = parseInt(headers['X-TOTAL-PAGES'], 10) || 0;
const more = currentPage < totalPages;
params.success({
results,
pagination: {
more,
},
});
})
.catch(params.error);
};
const groupsSelect = () => { const groupsSelect = () => {
loadCSSFile(gon.select2_css_path)
.then(() => {
// Needs to be accessible in rspec // Needs to be accessible in rspec
window.GROUP_SELECT_PER_PAGE = 20; window.GROUP_SELECT_PER_PAGE = 20;
$('.ajax-groups-select').each(function setAjaxGroupsSelect2() { $('.ajax-groups-select').each(function setAjaxGroupsSelect2() {
const $select = $(this); const $select = $(this);
const allAvailable = $select.data('allAvailable'); const allAvailable = $select.data('allAvailable');
...@@ -27,24 +52,7 @@ const groupsSelect = () => { ...@@ -27,24 +52,7 @@ const groupsSelect = () => {
dataType: 'json', dataType: 'json',
quietMillis: 250, quietMillis: 250,
transport(params) { transport(params) {
axios[params.type.toLowerCase()](params.url, { fetchGroups(params);
params: params.data,
})
.then(res => {
const results = res.data || [];
const headers = normalizeHeaders(res.headers);
const currentPage = parseInt(headers['X-PAGE'], 10) || 0;
const totalPages = parseInt(headers['X-TOTAL-PAGES'], 10) || 0;
const more = currentPage < totalPages;
params.success({
results,
pagination: {
more,
},
});
})
.catch(params.error);
}, },
data(search, page) { data(search, page) {
return { return {
...@@ -95,6 +103,8 @@ const groupsSelect = () => { ...@@ -95,6 +103,8 @@ const groupsSelect = () => {
dropdown.style.height = `${Math.floor(dropdown.scrollHeight)}px`; dropdown.style.height = `${Math.floor(dropdown.scrollHeight)}px`;
}); });
}); });
})
.catch(() => {});
}; };
export default () => { export default () => {
......
import $ from 'jquery'; import $ from 'jquery';
import { loadCSSFile } from '../lib/utils/css_utils';
let instanceCount = 0; let instanceCount = 0;
...@@ -12,6 +13,9 @@ class AutoWidthDropdownSelect { ...@@ -12,6 +13,9 @@ class AutoWidthDropdownSelect {
init() { init() {
const { dropdownClass } = this; const { dropdownClass } = this;
import(/* webpackChunkName: 'select2' */ 'select2/select2') import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => { .then(() => {
this.$selectElement.select2({ this.$selectElement.select2({
dropdownCssClass: dropdownClass, dropdownCssClass: dropdownClass,
...@@ -19,6 +23,8 @@ class AutoWidthDropdownSelect { ...@@ -19,6 +23,8 @@ class AutoWidthDropdownSelect {
}); });
}) })
.catch(() => {}); .catch(() => {});
})
.catch(() => {});
return this; return this;
} }
......
...@@ -2,6 +2,7 @@ import $ from 'jquery'; ...@@ -2,6 +2,7 @@ import $ from 'jquery';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils'; import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import UsersSelect from './users_select'; import UsersSelect from './users_select';
import { loadCSSFile } from './lib/utils/css_utils';
export default class IssuableContext { export default class IssuableContext {
constructor(currentUser) { constructor(currentUser) {
...@@ -9,6 +10,9 @@ export default class IssuableContext { ...@@ -9,6 +10,9 @@ export default class IssuableContext {
this.reviewersSelect = new UsersSelect(currentUser, '.js-reviewer-search'); this.reviewersSelect = new UsersSelect(currentUser, '.js-reviewer-search');
import(/* webpackChunkName: 'select2' */ 'select2/select2') import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => { .then(() => {
$('select.select2').select2({ $('select.select2').select2({
width: 'resolve', width: 'resolve',
...@@ -16,6 +20,8 @@ export default class IssuableContext { ...@@ -16,6 +20,8 @@ export default class IssuableContext {
}); });
}) })
.catch(() => {}); .catch(() => {});
})
.catch(() => {});
$('.issuable-sidebar .inline-update').on('change', 'select', function onClickSelect() { $('.issuable-sidebar .inline-update').on('change', 'select', function onClickSelect() {
return $(this).submit(); return $(this).submit();
......
...@@ -7,6 +7,7 @@ import ZenMode from './zen_mode'; ...@@ -7,6 +7,7 @@ import ZenMode from './zen_mode';
import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select'; import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select';
import { parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility'; import { parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility';
import { queryToObject, objectToQuery } from './lib/utils/url_utility'; import { queryToObject, objectToQuery } from './lib/utils/url_utility';
import { loadCSSFile } from './lib/utils/css_utils';
const MR_SOURCE_BRANCH = 'merge_request[source_branch]'; const MR_SOURCE_BRANCH = 'merge_request[source_branch]';
const MR_TARGET_BRANCH = 'merge_request[target_branch]'; const MR_TARGET_BRANCH = 'merge_request[target_branch]';
...@@ -183,6 +184,9 @@ export default class IssuableForm { ...@@ -183,6 +184,9 @@ export default class IssuableForm {
initTargetBranchDropdown() { initTargetBranchDropdown() {
import(/* webpackChunkName: 'select2' */ 'select2/select2') import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => { .then(() => {
this.$targetBranchSelect.select2({ this.$targetBranchSelect.select2({
...AutoWidthDropdownSelect.selectOptions('js-target-branch-select'), ...AutoWidthDropdownSelect.selectOptions('js-target-branch-select'),
...@@ -216,5 +220,7 @@ export default class IssuableForm { ...@@ -216,5 +220,7 @@ export default class IssuableForm {
}); });
}) })
.catch(() => {}); .catch(() => {});
})
.catch(() => {});
} }
} }
...@@ -4,8 +4,11 @@ import $ from 'jquery'; ...@@ -4,8 +4,11 @@ import $ from 'jquery';
import Api from './api'; import Api from './api';
import ProjectSelectComboButton from './project_select_combo_button'; import ProjectSelectComboButton from './project_select_combo_button';
import { s__ } from './locale'; import { s__ } from './locale';
import { loadCSSFile } from './lib/utils/css_utils';
const projectSelect = () => { const projectSelect = () => {
loadCSSFile(gon.select2_css_path)
.then(() => {
$('.ajax-project-select').each(function(i, select) { $('.ajax-project-select').each(function(i, select) {
let placeholder; let placeholder;
const simpleFilter = $(select).data('simpleFilter') || false; const simpleFilter = $(select).data('simpleFilter') || false;
...@@ -98,6 +101,7 @@ const projectSelect = () => { ...@@ -98,6 +101,7 @@ const projectSelect = () => {
}, },
initSelection(el, callback) { initSelection(el, callback) {
// eslint-disable-next-line promise/no-nesting
return Api.project(el.val()).then(({ data }) => callback(data)); return Api.project(el.val()).then(({ data }) => callback(data));
}, },
...@@ -108,6 +112,8 @@ const projectSelect = () => { ...@@ -108,6 +112,8 @@ const projectSelect = () => {
if (isInstantiated || simpleFilter) return select; if (isInstantiated || simpleFilter) return select;
return new ProjectSelectComboButton(select); return new ProjectSelectComboButton(select);
}); });
})
.catch(() => {});
}; };
export default () => { export default () => {
......
import $ from 'jquery'; import $ from 'jquery';
import AccessorUtilities from './lib/utils/accessor'; import AccessorUtilities from './lib/utils/accessor';
import { loadCSSFile } from './lib/utils/css_utils';
export default class ProjectSelectComboButton { export default class ProjectSelectComboButton {
constructor(select) { constructor(select) {
...@@ -45,12 +46,17 @@ export default class ProjectSelectComboButton { ...@@ -45,12 +46,17 @@ export default class ProjectSelectComboButton {
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
openDropdown(event) { openDropdown(event) {
import(/* webpackChunkName: 'select2' */ 'select2/select2') import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => { .then(() => {
$(event.currentTarget) $(event.currentTarget)
.siblings('.project-item-select') .siblings('.project-item-select')
.select2('open'); .select2('open');
}) })
.catch(() => {}); .catch(() => {});
})
.catch(() => {});
} }
selectProject() { selectProject() {
......
...@@ -15,6 +15,7 @@ import { parseBoolean, spriteIcon } from '../lib/utils/common_utils'; ...@@ -15,6 +15,7 @@ import { parseBoolean, spriteIcon } from '../lib/utils/common_utils';
import { getAjaxUsersSelectOptions, getAjaxUsersSelectParams } from './utils'; import { getAjaxUsersSelectOptions, getAjaxUsersSelectParams } from './utils';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown'; import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
import { fixTitle, dispose } from '~/tooltips'; import { fixTitle, dispose } from '~/tooltips';
import { loadCSSFile } from '../lib/utils/css_utils';
// TODO: remove eventHub hack after code splitting refactor // TODO: remove eventHub hack after code splitting refactor
window.emitSidebarEvent = window.emitSidebarEvent || $.noop; window.emitSidebarEvent = window.emitSidebarEvent || $.noop;
...@@ -591,6 +592,9 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -591,6 +592,9 @@ function UsersSelect(currentUser, els, options = {}) {
if ($('.ajax-users-select').length) { if ($('.ajax-users-select').length) {
import(/* webpackChunkName: 'select2' */ 'select2/select2') import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => { .then(() => {
$('.ajax-users-select').each((i, select) => { $('.ajax-users-select').each((i, select) => {
const options = getAjaxUsersSelectOptions($(select), AJAX_USERS_SELECT_OPTIONS_MAP); const options = getAjaxUsersSelectOptions($(select), AJAX_USERS_SELECT_OPTIONS_MAP);
...@@ -680,6 +684,8 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -680,6 +684,8 @@ function UsersSelect(currentUser, els, options = {}) {
}); });
}) })
.catch(() => {}); .catch(() => {});
})
.catch(() => {});
} }
} }
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
// directory. // directory.
@import '@gitlab/at.js/dist/css/jquery.atwho'; @import '@gitlab/at.js/dist/css/jquery.atwho';
@import 'dropzone/dist/basic'; @import 'dropzone/dist/basic';
@import 'select2';
// GitLab UI framework // GitLab UI framework
@import 'framework'; @import 'framework';
......
...@@ -135,7 +135,6 @@ hr { ...@@ -135,7 +135,6 @@ hr {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
> div:not(.block):not(.select2-display-none),
.str-truncated { .str-truncated {
display: inline; display: inline;
} }
......
...@@ -133,11 +133,6 @@ label { ...@@ -133,11 +133,6 @@ label {
} }
.input-group { .input-group {
.select2-container {
display: table-cell;
max-width: 180px;
}
.input-group-prepend, .input-group-prepend,
.input-group-append { .input-group-append {
background-color: $input-group-addon-bg; background-color: $input-group-addon-bg;
......
/** Select2 selectbox style override **/
.select2-container {
width: 100% !important;
&.input-md,
&.input-lg {
display: block;
}
}
.select2-container,
.select2-container.select2-drop-above {
.select2-choice {
background: $white;
color: $gl-text-color;
border-color: $input-border;
height: 34px;
padding: $gl-vert-padding $gl-input-padding;
font-size: $gl-font-size;
line-height: 1.42857143;
border-radius: $border-radius-base;
.select2-arrow {
background-image: none;
background-color: transparent;
border: 0;
padding-top: 12px;
padding-right: 20px;
font-size: 10px;
b {
display: none;
}
&::after {
content: '\f078';
position: absolute;
z-index: 1;
text-align: center;
pointer-events: none;
box-sizing: border-box;
color: $gray-darkest;
display: inline-block;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
.select2-chosen {
margin-right: 15px;
}
&:hover {
border-color: $gray-darkest;
color: $gl-text-color;
}
}
// Essentially we’re doing @include form-control-focus here (from
// bootstrap/scss/mixins/_forms.scss), except that the bootstrap mixin adds a
// `&:focus` selector and we’re never actually focusing the .select2-choice
// link nor the .select2-container, the Select2 library focuses an off-screen
// .select2-focusser element instead.
&.select2-container-active:not(.select2-dropdown-open) {
.select2-choice {
color: $input-focus-color;
background-color: $input-focus-bg;
border-color: $input-focus-border-color;
outline: 0;
}
// Reusable focus “glow” box-shadow
@mixin form-control-focus-glow {
@if $enable-shadows {
box-shadow: $input-box-shadow, $input-focus-box-shadow;
} @else {
box-shadow: $input-focus-box-shadow;
}
}
// Apply the focus “glow” shadow to the .select2-container if it also has
// the .block-truncated class as that applies an overflow: hidden, thereby
// hiding the glow of the nested .select2-choice element.
&.block-truncated {
@include form-control-focus-glow;
}
// Apply the glow directly to the .select2-choice link if we’re not
// block-truncating the container.
&:not(.block-truncated) .select2-choice {
@include form-control-focus-glow;
}
}
&.is-invalid {
~ .invalid-feedback {
display: block;
}
.select2-choices,
.select2-choice {
border-color: $red-500;
}
}
}
.select2-drop,
.select2-drop.select2-drop-above {
background: $white;
box-shadow: 0 2px 4px $dropdown-shadow-color;
border-radius: $border-radius-base;
border: 1px solid $border-color;
min-width: 175px;
color: $gl-text-color;
z-index: 999;
.modal-open & {
z-index: $zindex-modal + 200;
}
}
.select2-drop-mask {
z-index: 998;
.modal-open & {
z-index: $zindex-modal + 100;
}
}
.select2-drop.select2-drop-above.select2-drop-active {
border-top: 1px solid $border-color;
margin-top: -6px;
}
.select2-container-active {
.select2-choice,
.select2-choices {
box-shadow: none;
}
}
.select2-dropdown-open,
.select2-dropdown-open.select2-drop-above {
.select2-choice {
border-color: $gray-darkest;
outline: 0;
}
}
.select2-container-multi {
.select2-choices {
border-radius: $border-radius-default;
border-color: $input-border;
background: none;
.select2-search-field input {
padding: 5px $gl-input-padding;
height: auto;
font-family: inherit;
font-size: inherit;
}
.select2-search-choice {
margin: 5px 0 0 8px;
box-shadow: none;
border-color: $input-border;
color: $gl-text-color;
line-height: 15px;
background-color: $gray-light;
background-image: none;
padding: 3px 18px 3px 5px;
.select2-search-choice-close {
top: 5px;
left: initial;
right: 3px;
}
&.select2-search-choice-focus {
border-color: $gl-text-color;
}
}
}
}
.select2-drop-active {
margin-top: $dropdown-vertical-offset;
font-size: 14px;
.select2-results {
max-height: 350px;
}
}
.select2-search {
padding: $grid-size;
.select2-drop-auto-width & {
padding: $grid-size;
}
input {
padding: $grid-size;
background: transparent image-url('select2.png');
color: $gl-text-color;
background-clip: content-box;
background-origin: content-box;
background-repeat: no-repeat;
background-position: right 0 bottom 0 !important;
border: 1px solid $input-border;
border-radius: $border-radius-default;
line-height: 16px;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
&:focus {
border-color: $blue-300;
}
&.select2-active {
background-color: $white;
background-image: image-url('select2-spinner.gif') !important;
background-origin: content-box;
background-repeat: no-repeat;
background-position: right 6px center !important;
background-size: 16px 16px !important;
}
}
+ .select2-results {
padding-top: 0;
}
}
.select2-results {
margin: 0;
padding: #{$gl-padding / 2} 0;
.select2-no-results,
.select2-searching,
.select2-ajax-error,
.select2-selection-limit {
background: transparent;
padding: #{$gl-padding / 2} $gl-padding;
}
.select2-result-label,
.select2-more-results {
padding: #{$gl-padding / 2} $gl-padding;
}
.select2-highlighted {
background: transparent;
color: $gl-text-color;
.select2-result-label {
background: $gray-darker;
}
}
.select2-result {
padding: 0 1px;
}
li.select2-result-with-children > .select2-result-label {
font-weight: $gl-font-weight-bold;
color: $gl-text-color;
}
}
.ajax-users-select { .ajax-users-select {
width: 400px; width: 400px;
...@@ -282,14 +10,6 @@ ...@@ -282,14 +10,6 @@
} }
} }
.select2-highlighted {
.group-result {
.group-path {
color: $gray-700;
}
}
}
.group-result { .group-result {
.group-image { .group-image {
float: left; float: left;
...@@ -345,11 +65,3 @@ ...@@ -345,11 +65,3 @@
.ajax-users-dropdown { .ajax-users-dropdown {
min-width: 250px !important; min-width: 250px !important;
} }
.select2-result-selectable,
.select2-result-unselectable {
.select2-match {
font-weight: $gl-font-weight-bold;
text-decoration: none;
}
}
...@@ -74,10 +74,6 @@ ...@@ -74,10 +74,6 @@
justify-content: flex-end; justify-content: flex-end;
} }
.select2 {
float: right;
}
.encoding-selector, .encoding-selector,
.soft-wrap-toggle { .soft-wrap-toggle {
display: inline-block; display: inline-block;
......
...@@ -17,14 +17,6 @@ ...@@ -17,14 +17,6 @@
max-width: 300px; max-width: 300px;
} }
.import-namespace-select {
> .select2-choice {
border-radius: $border-radius-default 0 0 $border-radius-default;
position: relative;
left: 1px;
}
}
.import-slash-divider { .import-slash-divider {
background-color: $gray-lightest; background-color: $gray-lightest;
border: 1px solid $border-color; border: 1px solid $border-color;
......
...@@ -199,10 +199,6 @@ ...@@ -199,10 +199,6 @@
border: 0; border: 0;
} }
.select2-container span {
margin-top: 0;
}
&.assignee { &.assignee {
.author-link { .author-link {
display: block; display: block;
......
...@@ -92,6 +92,11 @@ ul.related-merge-requests > li { ...@@ -92,6 +92,11 @@ ul.related-merge-requests > li {
} }
} }
.issues-footer {
padding-top: $gl-padding;
padding-bottom: 37px;
}
.issues-nav-controls, .issues-nav-controls,
.new-branch-col { .new-branch-col {
font-size: 0; font-size: 0;
......
...@@ -10,12 +10,6 @@ ...@@ -10,12 +10,6 @@
} }
.input-group { .input-group {
.select2-container {
display: unset;
max-width: unset;
flex-grow: 1;
}
> div { > div {
&:last-child { &:last-child {
padding-right: 0; padding-right: 0;
...@@ -52,7 +46,6 @@ ...@@ -52,7 +46,6 @@
flex-grow: 1; flex-grow: 1;
} }
+ .select2 a,
+ .btn-default { + .btn-default {
border-radius: 0 $border-radius-base $border-radius-base 0; border-radius: 0 $border-radius-base $border-radius-base 0;
} }
...@@ -258,10 +251,6 @@ ...@@ -258,10 +251,6 @@
color: $gray-700; color: $gray-700;
} }
.transfer-project .select2-container {
min-width: 200px;
}
.deploy-key { .deploy-key {
// Ensure that the fingerprint does not overflow on small screens // Ensure that the fingerprint does not overflow on small screens
.fingerprint { .fingerprint {
...@@ -1057,11 +1046,6 @@ pre.light-well { ...@@ -1057,11 +1046,6 @@ pre.light-well {
margin-bottom: 0; margin-bottom: 0;
} }
} }
.select2-choice {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
} }
.project-home-empty { .project-home-empty {
......
<script> <script>
import $ from 'jquery'; import $ from 'jquery';
import 'select2/select2';
import { escape, debounce } from 'lodash'; import { escape, debounce } from 'lodash';
import Api from 'ee/api'; import Api from 'ee/api';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { TYPE_USER, TYPE_GROUP } from '../constants'; import { TYPE_USER, TYPE_GROUP } from '../constants';
import { renderAvatar } from '~/helpers/avatar_helper'; import { renderAvatar } from '~/helpers/avatar_helper';
import { loadCSSFile } from '~/lib/utils/css_utils';
function addType(type) { function addType(type) {
return items => items.map(obj => Object.assign(obj, { type })); return items => items.map(obj => Object.assign(obj, { type }));
...@@ -97,6 +97,11 @@ export default { ...@@ -97,6 +97,11 @@ export default {
}, },
}, },
mounted() { mounted() {
import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => {
$(this.$refs.input) $(this.$refs.input)
.select2({ .select2({
placeholder: __('Search users or groups'), placeholder: __('Search users or groups'),
...@@ -105,10 +110,17 @@ export default { ...@@ -105,10 +110,17 @@ export default {
closeOnSelect: false, closeOnSelect: false,
formatResult, formatResult,
formatSelection, formatSelection,
query: debounce(({ term, callback }) => this.fetchGroupsAndUsers(term).then(callback), 250), query: debounce(({ term, callback }) => {
// eslint-disable-next-line promise/no-nesting
return this.fetchGroupsAndUsers(term).then(callback);
}, 250),
id: ({ type, id }) => `${type}${id}`, id: ({ type, id }) => `${type}${id}`,
}) })
.on('change', e => this.onChange(e)); .on('change', e => this.onChange(e));
})
.catch(() => {});
})
.catch(() => {});
}, },
beforeDestroy() { beforeDestroy() {
$(this.$refs.input).select2('destroy'); $(this.$refs.input).select2('destroy');
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import $ from 'jquery'; import $ from 'jquery';
import Api from 'ee/api'; import Api from 'ee/api';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { loadCSSFile } from '~/lib/utils/css_utils';
export default function initLDAPGroupsSelect() { export default function initLDAPGroupsSelect() {
const ldapGroupResult = function(group) { const ldapGroupResult = function(group) {
...@@ -12,6 +13,9 @@ export default function initLDAPGroupsSelect() { ...@@ -12,6 +13,9 @@ export default function initLDAPGroupsSelect() {
return group.cn; return group.cn;
}; };
import(/* webpackChunkName: 'select2' */ 'select2/select2') import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => { .then(() => {
$('.ajax-ldap-groups-select').each((i, select) => { $('.ajax-ldap-groups-select').each((i, select) => {
$(select).select2({ $(select).select2({
...@@ -47,6 +51,8 @@ export default function initLDAPGroupsSelect() { ...@@ -47,6 +51,8 @@ export default function initLDAPGroupsSelect() {
}); });
}) })
.catch(() => {}); .catch(() => {});
})
.catch(() => {});
$('#ldap_group_link_provider').on('change', () => { $('#ldap_group_link_provider').on('change', () => {
$('.ajax-ldap-groups-select').select2('data', null); $('.ajax-ldap-groups-select').select2('data', null);
......
import '~/pages/admin/application_settings/index'; import '~/pages/admin/application_settings/index';
import 'select2/select2';
import $ from 'jquery'; import $ from 'jquery';
import groupsSelect from '~/groups_select'; import groupsSelect from '~/groups_select';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import Api from '~/api'; import Api from '~/api';
import { loadCSSFile } from '~/lib/utils/css_utils';
const onLimitCheckboxChange = (checked, $limitByNamespaces, $limitByProjects) => { const onLimitCheckboxChange = (checked, $limitByNamespaces, $limitByProjects) => {
$limitByNamespaces.find('.select2').select2('data', null); $limitByNamespaces.find('.select2').select2('data', null);
...@@ -53,7 +53,12 @@ $container ...@@ -53,7 +53,12 @@ $container
), ),
); );
$container import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => {
$container
.find('.js-elasticsearch-namespaces') .find('.js-elasticsearch-namespaces')
.select2( .select2(
getDropdownConfig( getDropdownConfig(
...@@ -63,7 +68,7 @@ $container ...@@ -63,7 +68,7 @@ $container
), ),
); );
$container $container
.find('.js-elasticsearch-projects') .find('.js-elasticsearch-projects')
.select2( .select2(
getDropdownConfig( getDropdownConfig(
...@@ -72,3 +77,7 @@ $container ...@@ -72,3 +77,7 @@ $container
'name_with_namespace', 'name_with_namespace',
), ),
); );
})
.catch(() => {});
})
.catch(() => {});
import 'select2/select2';
import $ from 'jquery'; import $ from 'jquery';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import PersistentUserCallout from '~/persistent_user_callout'; import PersistentUserCallout from '~/persistent_user_callout';
import { loadCSSFile } from '~/lib/utils/css_utils';
const onLimitCheckboxChange = (checked, $limitByNamespaces, $limitByProjects) => { const onLimitCheckboxChange = (checked, $limitByNamespaces, $limitByProjects) => {
$limitByNamespaces.find('.select2').select2('data', null); $limitByNamespaces.find('.select2').select2('data', null);
...@@ -52,7 +52,12 @@ $container ...@@ -52,7 +52,12 @@ $container
), ),
); );
$container import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => {
$container
.find('.js-elasticsearch-namespaces') .find('.js-elasticsearch-namespaces')
.select2( .select2(
getDropdownConfig( getDropdownConfig(
...@@ -61,7 +66,7 @@ $container ...@@ -61,7 +66,7 @@ $container
), ),
); );
$container $container
.find('.js-elasticsearch-projects') .find('.js-elasticsearch-projects')
.select2( .select2(
getDropdownConfig( getDropdownConfig(
...@@ -69,3 +74,7 @@ $container ...@@ -69,3 +74,7 @@ $container
'/-/autocomplete/project_routes.json', '/-/autocomplete/project_routes.json',
), ),
); );
})
.catch(() => {});
})
.catch(() => {});
...@@ -2,6 +2,7 @@ import $ from 'jquery'; ...@@ -2,6 +2,7 @@ import $ from 'jquery';
import Api from '~/api'; import Api from '~/api';
import { sprintf, __ } from '~/locale'; import { sprintf, __ } from '~/locale';
import { sanitizeItem } from '~/frequent_items/utils'; import { sanitizeItem } from '~/frequent_items/utils';
import { loadCSSFile } from '~/lib/utils/css_utils';
const formatResult = selectedItem => { const formatResult = selectedItem => {
if (selectedItem.path_with_namespace) { if (selectedItem.path_with_namespace) {
...@@ -23,13 +24,7 @@ const formatSelection = selectedItem => { ...@@ -23,13 +24,7 @@ const formatSelection = selectedItem => {
return __('All groups and projects'); return __('All groups and projects');
}; };
const AdminEmailSelect = () => { const QueryAdmin = query => {
$('.ajax-admin-email-select').each((i, select) =>
$(select).select2({
placeholder: __('Select group or project'),
multiple: $(select).hasClass('multiselect'),
minimumInputLength: 0,
query(query) {
const groupsFetch = Api.groups(query.term, {}); const groupsFetch = Api.groups(query.term, {});
const projectsFetch = Api.projects(query.term, { const projectsFetch = Api.projects(query.term, {
order_by: 'id', order_by: 'id',
...@@ -44,6 +39,18 @@ const AdminEmailSelect = () => { ...@@ -44,6 +39,18 @@ const AdminEmailSelect = () => {
results: data, results: data,
}); });
}); });
};
const AdminEmailSelect = () => {
loadCSSFile(gon.select2_css_path)
.then(() => {
$('.ajax-admin-email-select').each((i, select) =>
$(select).select2({
placeholder: __('Select group or project'),
multiple: $(select).hasClass('multiselect'),
minimumInputLength: 0,
query(query) {
QueryAdmin(query);
}, },
id(object) { id(object) {
if (object.path_with_namespace) { if (object.path_with_namespace) {
...@@ -65,6 +72,8 @@ const AdminEmailSelect = () => { ...@@ -65,6 +72,8 @@ const AdminEmailSelect = () => {
}, },
}), }),
); );
})
.catch(() => {});
}; };
export default () => export default () =>
......
...@@ -2,6 +2,7 @@ import $ from 'jquery'; ...@@ -2,6 +2,7 @@ import $ from 'jquery';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { deprecatedCreateFlash as Flash } from '~/flash'; import { deprecatedCreateFlash as Flash } from '~/flash';
import MirrorRepos from '~/mirrors/mirror_repos'; import MirrorRepos from '~/mirrors/mirror_repos';
import { loadCSSFile } from '~/lib/utils/css_utils';
export default class EEMirrorRepos extends MirrorRepos { export default class EEMirrorRepos extends MirrorRepos {
constructor(...args) { constructor(...args) {
...@@ -77,6 +78,9 @@ export default class EEMirrorRepos extends MirrorRepos { ...@@ -77,6 +78,9 @@ export default class EEMirrorRepos extends MirrorRepos {
initSelect2() { initSelect2() {
import(/* webpackChunkName: 'select2' */ 'select2/select2') import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => { .then(() => {
$('.js-mirror-user', this.$form).select2({ $('.js-mirror-user', this.$form).select2({
width: 'resolve', width: 'resolve',
...@@ -84,6 +88,8 @@ export default class EEMirrorRepos extends MirrorRepos { ...@@ -84,6 +88,8 @@ export default class EEMirrorRepos extends MirrorRepos {
}); });
}) })
.catch(() => {}); .catch(() => {});
})
.catch(() => {});
} }
registerUpdateListeners() { registerUpdateListeners() {
......
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import $ from 'jquery'; import $ from 'jquery';
import 'select2/select2';
import Api from 'ee/api'; import Api from 'ee/api';
import ApproversSelect from 'ee/approvals/components/approvers_select.vue'; import ApproversSelect from 'ee/approvals/components/approvers_select.vue';
import { TYPE_USER, TYPE_GROUP } from 'ee/approvals/constants'; import { TYPE_USER, TYPE_GROUP } from 'ee/approvals/constants';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
const TEST_PROJECT_ID = '17'; const TEST_PROJECT_ID = '17';
const TEST_GROUP_AVATAR = `${TEST_HOST}/group-avatar.png`; const TEST_GROUP_AVATAR = `${TEST_HOST}/group-avatar.png`;
...@@ -51,19 +53,21 @@ describe('Approvals ApproversSelect', () => { ...@@ -51,19 +53,21 @@ describe('Approvals ApproversSelect', () => {
let wrapper; let wrapper;
let $input; let $input;
const factory = (options = {}) => { const factory = async (options = {}) => {
const propsData = { const propsData = {
projectId: TEST_PROJECT_ID, projectId: TEST_PROJECT_ID,
...options.propsData, ...options.propsData,
}; };
wrapper = shallowMount(ApproversSelect, { wrapper = await shallowMount(ApproversSelect, {
...options, ...options,
propsData, propsData,
localVue, localVue,
attachToDocument: true, attachToDocument: true,
}); });
await waitForPromises();
$input = $(wrapper.vm.$refs.input); $input = $(wrapper.vm.$refs.input);
}; };
const search = (term = '') => { const search = (term = '') => {
...@@ -80,16 +84,16 @@ describe('Approvals ApproversSelect', () => { ...@@ -80,16 +84,16 @@ describe('Approvals ApproversSelect', () => {
wrapper.destroy(); wrapper.destroy();
}); });
it('renders select2 input', () => { it('renders select2 input', async () => {
expect(select2Container()).toBe(null); expect(select2Container()).toBe(null);
factory(); await factory();
expect(select2Container()).not.toBe(null); expect(select2Container()).not.toBe(null);
}); });
it('queries and displays groups and users', done => { it('queries and displays groups and users', async done => {
factory(); await factory();
const expected = TEST_GROUPS.concat(TEST_USERS) const expected = TEST_GROUPS.concat(TEST_USERS)
.map(({ id, ...obj }) => obj) .map(({ id, ...obj }) => obj)
...@@ -110,8 +114,8 @@ describe('Approvals ApproversSelect', () => { ...@@ -110,8 +114,8 @@ describe('Approvals ApproversSelect', () => {
describe('with search term', () => { describe('with search term', () => {
const term = 'lorem'; const term = 'lorem';
beforeEach(done => { beforeEach(async done => {
factory(); await factory();
waitForEvent($input, 'select2-loaded') waitForEvent($input, 'select2-loaded')
.then(jest.runOnlyPendingTimers) .then(jest.runOnlyPendingTimers)
...@@ -136,8 +140,8 @@ describe('Approvals ApproversSelect', () => { ...@@ -136,8 +140,8 @@ describe('Approvals ApproversSelect', () => {
const skipGroupIds = [7, 8]; const skipGroupIds = [7, 8];
const skipUserIds = [9, 10]; const skipUserIds = [9, 10];
beforeEach(done => { beforeEach(async done => {
factory({ await factory({
propsData: { propsData: {
skipGroupIds, skipGroupIds,
skipUserIds, skipUserIds,
...@@ -166,8 +170,8 @@ describe('Approvals ApproversSelect', () => { ...@@ -166,8 +170,8 @@ describe('Approvals ApproversSelect', () => {
}); });
}); });
it('emits input when data changes', done => { it('emits input when data changes', async done => {
factory(); await factory();
const expectedFinal = [ const expectedFinal = [
{ ...TEST_USERS[0], type: TYPE_USER }, { ...TEST_USERS[0], type: TYPE_USER },
......
This diff is collapsed.
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