Commit 2ac27a96 authored by Phil Hughes's avatar Phil Hughes

Merge branch 'import-export-users_select' into 'master'

Import export users select

See merge request !11286
parents 8c4e4020 05278b2f
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
/* global NotificationsForm */ /* global NotificationsForm */
/* global TreeView */ /* global TreeView */
/* global NotificationsDropdown */ /* global NotificationsDropdown */
/* global UsersSelect */
/* global GroupAvatar */ /* global GroupAvatar */
/* global LineHighlighter */ /* global LineHighlighter */
/* global ProjectFork */ /* global ProjectFork */
...@@ -52,6 +51,7 @@ import ShortcutsWiki from './shortcuts_wiki'; ...@@ -52,6 +51,7 @@ import ShortcutsWiki from './shortcuts_wiki';
import Pipelines from './pipelines'; import Pipelines from './pipelines';
import BlobViewer from './blob/viewer/index'; import BlobViewer from './blob/viewer/index';
import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select'; import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select';
import UsersSelect from './users_select';
const ShortcutsBlob = require('./shortcuts_blob'); const ShortcutsBlob = require('./shortcuts_blob');
...@@ -113,6 +113,7 @@ const ShortcutsBlob = require('./shortcuts_blob'); ...@@ -113,6 +113,7 @@ const ShortcutsBlob = require('./shortcuts_blob');
case 'projects:boards:show': case 'projects:boards:show':
case 'projects:boards:index': case 'projects:boards:index':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
new UsersSelect();
break; break;
case 'projects:builds:show': case 'projects:builds:show':
new Build(); new Build();
...@@ -127,6 +128,7 @@ const ShortcutsBlob = require('./shortcuts_blob'); ...@@ -127,6 +128,7 @@ const ShortcutsBlob = require('./shortcuts_blob');
prefixId: page === 'projects:merge_requests:index' ? 'merge_request_' : 'issue_', prefixId: page === 'projects:merge_requests:index' ? 'merge_request_' : 'issue_',
}); });
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
new UsersSelect();
break; break;
case 'projects:issues:show': case 'projects:issues:show':
new Issue(); new Issue();
...@@ -139,6 +141,10 @@ const ShortcutsBlob = require('./shortcuts_blob'); ...@@ -139,6 +141,10 @@ const ShortcutsBlob = require('./shortcuts_blob');
new Milestone(); new Milestone();
new Sidebar(); new Sidebar();
break; break;
case 'groups:issues':
case 'groups:merge_requests':
new UsersSelect();
break;
case 'dashboard:todos:index': case 'dashboard:todos:index':
new gl.Todos(); new gl.Todos();
break; break;
...@@ -223,6 +229,10 @@ const ShortcutsBlob = require('./shortcuts_blob'); ...@@ -223,6 +229,10 @@ const ShortcutsBlob = require('./shortcuts_blob');
case 'dashboard:activity': case 'dashboard:activity':
new gl.Activities(); new gl.Activities();
break; break;
case 'dashboard:issues':
case 'dashboard:merge_requests':
new UsersSelect();
break;
case 'projects:commit:show': case 'projects:commit:show':
new Commit(); new Commit();
new gl.Diff(); new gl.Diff();
...@@ -377,6 +387,9 @@ const ShortcutsBlob = require('./shortcuts_blob'); ...@@ -377,6 +387,9 @@ const ShortcutsBlob = require('./shortcuts_blob');
new LineHighlighter(); new LineHighlighter();
new BlobViewer(); new BlobViewer();
break; break;
case 'import:fogbugz:new_user_map':
new UsersSelect();
break;
} }
switch (path.first()) { switch (path.first()) {
case 'sessions': case 'sessions':
......
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, comma-dangle, quotes, prefer-arrow-callback, consistent-return, one-var, no-var, one-var-declaration-per-line, no-underscore-dangle, max-len */ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, comma-dangle, quotes, prefer-arrow-callback, consistent-return, one-var, no-var, one-var-declaration-per-line, no-underscore-dangle, max-len */
/* global UsersSelect */
/* global bp */ /* global bp */
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import UsersSelect from './users_select';
(function() { (function() {
this.IssuableContext = (function() { this.IssuableContext = (function() {
......
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-new, quotes, object-shorthand, no-unused-vars, comma-dangle, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, max-len */ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-new, quotes, object-shorthand, no-unused-vars, comma-dangle, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, max-len */
/* global GitLab */ /* global GitLab */
/* global UsersSelect */
/* global ZenMode */ /* global ZenMode */
/* global Autosave */ /* global Autosave */
/* global dateFormat */ /* global dateFormat */
/* global Pikaday */ /* global Pikaday */
import UsersSelect from './users_select';
(function() { (function() {
this.IssuableForm = (function() { this.IssuableForm = (function() {
IssuableForm.prototype.issueMoveConfirmMsg = 'Are you sure you want to move this issue to another project?'; IssuableForm.prototype.issueMoveConfirmMsg = 'Are you sure you want to move this issue to another project?';
......
/* eslint-disable class-methods-use-this, no-unneeded-ternary, quote-props */ /* eslint-disable class-methods-use-this, no-unneeded-ternary, quote-props */
/* global UsersSelect */
import UsersSelect from './users_select';
class Todos { class Todos {
constructor() { constructor() {
......
...@@ -5,655 +5,649 @@ ...@@ -5,655 +5,649 @@
// 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;
(function() { function UsersSelect(currentUser, els) {
const slice = [].slice; var $els;
this.users = this.users.bind(this);
this.UsersSelect = (function() { this.user = this.user.bind(this);
function UsersSelect(currentUser, els) { this.usersPath = "/autocomplete/users.json";
var $els; this.userPath = "/autocomplete/users/:id.json";
this.users = this.users.bind(this); if (currentUser != null) {
this.user = this.user.bind(this); if (typeof currentUser === 'object') {
this.usersPath = "/autocomplete/users.json"; this.currentUser = currentUser;
this.userPath = "/autocomplete/users/:id.json"; } else {
if (currentUser != null) { this.currentUser = JSON.parse(currentUser);
if (typeof currentUser === 'object') { }
this.currentUser = currentUser; }
} else {
this.currentUser = JSON.parse(currentUser); $els = $(els);
if (!els) {
$els = $('.js-user-search');
}
$els.each((function(_this) {
return function(i, dropdown) {
var options = {};
var $block, $collapsedSidebar, $dropdown, $loading, $selectbox, $value, abilityName, assignTo, assigneeTemplate, collapsedAssigneeTemplate, defaultLabel, defaultNullUser, firstUser, issueURL, selectedId, selectedIdDefault, showAnyUser, showNullUser, showMenuAbove;
$dropdown = $(dropdown);
options.projectId = $dropdown.data('project-id');
options.groupId = $dropdown.data('group-id');
options.showCurrentUser = $dropdown.data('current-user');
options.todoFilter = $dropdown.data('todo-filter');
options.todoStateFilter = $dropdown.data('todo-state-filter');
showNullUser = $dropdown.data('null-user');
defaultNullUser = $dropdown.data('null-user-default');
showMenuAbove = $dropdown.data('showMenuAbove');
showAnyUser = $dropdown.data('any-user');
firstUser = $dropdown.data('first-user');
options.authorId = $dropdown.data('author-id');
defaultLabel = $dropdown.data('default-label');
issueURL = $dropdown.data('issueUpdate');
$selectbox = $dropdown.closest('.selectbox');
$block = $selectbox.closest('.block');
abilityName = $dropdown.data('ability-name');
$value = $block.find('.value');
$collapsedSidebar = $block.find('.sidebar-collapsed-user');
$loading = $block.find('.block-loading').fadeOut();
selectedIdDefault = (defaultNullUser && showNullUser) ? 0 : null;
selectedId = $dropdown.data('selected') || selectedIdDefault;
const assignYourself = function () {
const unassignedSelected = $dropdown.closest('.selectbox')
.find(`input[name='${$dropdown.data('field-name')}'][value=0]`);
if (unassignedSelected) {
unassignedSelected.remove();
} }
}
$els = $(els); // Save current selected user to the DOM
const input = document.createElement('input');
input.type = 'hidden';
input.name = $dropdown.data('field-name');
const currentUserInfo = $dropdown.data('currentUserInfo');
if (currentUserInfo) {
input.value = currentUserInfo.id;
input.dataset.meta = currentUserInfo.name;
} else if (_this.currentUser) {
input.value = _this.currentUser.id;
}
if (!els) { if ($selectbox) {
$els = $('.js-user-search'); $dropdown.parent().before(input);
} else {
$dropdown.after(input);
}
};
if ($block[0]) {
$block[0].addEventListener('assignYourself', assignYourself);
} }
$els.each((function(_this) { const getSelectedUserInputs = function() {
return function(i, dropdown) { return $selectbox
var options = {}; .find(`input[name="${$dropdown.data('field-name')}"]`);
var $block, $collapsedSidebar, $dropdown, $loading, $selectbox, $value, abilityName, assignTo, assigneeTemplate, collapsedAssigneeTemplate, defaultLabel, defaultNullUser, firstUser, issueURL, selectedId, selectedIdDefault, showAnyUser, showNullUser, showMenuAbove; };
$dropdown = $(dropdown);
options.projectId = $dropdown.data('project-id'); const getSelected = function() {
options.groupId = $dropdown.data('group-id'); return getSelectedUserInputs()
options.showCurrentUser = $dropdown.data('current-user'); .map((index, input) => parseInt(input.value, 10))
options.todoFilter = $dropdown.data('todo-filter'); .get();
options.todoStateFilter = $dropdown.data('todo-state-filter'); };
showNullUser = $dropdown.data('null-user');
defaultNullUser = $dropdown.data('null-user-default'); const checkMaxSelect = function() {
showMenuAbove = $dropdown.data('showMenuAbove'); const maxSelect = $dropdown.data('max-select');
showAnyUser = $dropdown.data('any-user'); if (maxSelect) {
firstUser = $dropdown.data('first-user'); const selected = getSelected();
options.authorId = $dropdown.data('author-id');
defaultLabel = $dropdown.data('default-label'); if (selected.length > maxSelect) {
issueURL = $dropdown.data('issueUpdate'); const firstSelectedId = selected[0];
$selectbox = $dropdown.closest('.selectbox'); const firstSelected = $dropdown.closest('.selectbox')
$block = $selectbox.closest('.block'); .find(`input[name='${$dropdown.data('field-name')}'][value=${firstSelectedId}]`);
abilityName = $dropdown.data('ability-name');
$value = $block.find('.value'); firstSelected.remove();
$collapsedSidebar = $block.find('.sidebar-collapsed-user'); emitSidebarEvent('sidebar.removeAssignee', {
$loading = $block.find('.block-loading').fadeOut(); id: firstSelectedId,
selectedIdDefault = (defaultNullUser && showNullUser) ? 0 : null; });
selectedId = $dropdown.data('selected') || selectedIdDefault; }
}
const assignYourself = function () { };
const unassignedSelected = $dropdown.closest('.selectbox')
.find(`input[name='${$dropdown.data('field-name')}'][value=0]`); const getMultiSelectDropdownTitle = function(selectedUser, isSelected) {
const selectedUsers = getSelected()
if (unassignedSelected) { .filter(u => u !== 0);
unassignedSelected.remove();
} const firstUser = getSelectedUserInputs()
.map((index, input) => ({
name: input.dataset.meta,
value: parseInt(input.value, 10),
}))
.filter(u => u.id !== 0)
.get(0);
if (selectedUsers.length === 0) {
return 'Unassigned';
} else if (selectedUsers.length === 1) {
return firstUser.name;
} else if (isSelected) {
const otherSelected = selectedUsers.filter(s => s !== selectedUser.id);
return `${selectedUser.name} + ${otherSelected.length} more`;
} else {
return `${firstUser.name} + ${selectedUsers.length - 1} more`;
}
};
// Save current selected user to the DOM $('.assign-to-me-link').on('click', (e) => {
const input = document.createElement('input'); e.preventDefault();
input.type = 'hidden'; $(e.currentTarget).hide();
input.name = $dropdown.data('field-name');
const currentUserInfo = $dropdown.data('currentUserInfo'); if ($dropdown.data('multiSelect')) {
assignYourself();
checkMaxSelect();
if (currentUserInfo) { const currentUserInfo = $dropdown.data('currentUserInfo');
input.value = currentUserInfo.id; $dropdown.find('.dropdown-toggle-text').text(getMultiSelectDropdownTitle(currentUserInfo)).removeClass('is-default');
input.dataset.meta = currentUserInfo.name; } else {
} else if (_this.currentUser) { const $input = $(`input[name="${$dropdown.data('field-name')}"]`);
input.value = _this.currentUser.id; $input.val(gon.current_user_id);
} selectedId = $input.val();
$dropdown.find('.dropdown-toggle-text').text(gon.current_user_fullname).removeClass('is-default');
}
});
if ($selectbox) { $block.on('click', '.js-assign-yourself', (e) => {
$dropdown.parent().before(input); e.preventDefault();
} else { return assignTo(_this.currentUser.id);
$dropdown.after(input); });
}
};
if ($block[0]) { assignTo = function(selected) {
$block[0].addEventListener('assignYourself', assignYourself); var data;
data = {};
data[abilityName] = {};
data[abilityName].assignee_id = selected != null ? selected : null;
$loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown');
return $.ajax({
type: 'PUT',
dataType: 'json',
url: issueURL,
data: data
}).done(function(data) {
var user;
$dropdown.trigger('loaded.gl.dropdown');
$loading.fadeOut();
if (data.assignee) {
user = {
name: data.assignee.name,
username: data.assignee.username,
avatar: data.assignee.avatar_url
};
} else {
user = {
name: 'Unassigned',
username: '',
avatar: ''
};
} }
$value.html(assigneeTemplate(user));
const getSelectedUserInputs = function() { $collapsedSidebar.attr('title', user.name).tooltip('fixTitle');
return $selectbox return $collapsedSidebar.html(collapsedAssigneeTemplate(user));
.find(`input[name="${$dropdown.data('field-name')}"]`); });
}; };
collapsedAssigneeTemplate = _.template('<% if( avatar ) { %> <a class="author_link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>');
const getSelected = function() { assigneeTemplate = _.template('<% if (username) { %> <a class="author_link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself"> No assignee - <a href="#" class="js-assign-yourself"> assign yourself </a> </span> <% } %>');
return getSelectedUserInputs() return $dropdown.glDropdown({
.map((index, input) => parseInt(input.value, 10)) showMenuAbove: showMenuAbove,
.get(); data: function(term, callback) {
}; var isAuthorFilter;
isAuthorFilter = $('.js-author-search');
const checkMaxSelect = function() { return _this.users(term, options, function(users) {
const maxSelect = $dropdown.data('max-select'); // GitLabDropdownFilter returns this.instance
if (maxSelect) { // GitLabDropdownRemote returns this.options.instance
const selected = getSelected(); const glDropdown = this.instance || this.options.instance;
glDropdown.options.processData(term, users, callback);
if (selected.length > maxSelect) { }.bind(this));
const firstSelectedId = selected[0]; },
const firstSelected = $dropdown.closest('.selectbox') processData: function(term, users, callback) {
.find(`input[name='${$dropdown.data('field-name')}'][value=${firstSelectedId}]`); let anyUser;
let index;
firstSelected.remove(); let j;
emitSidebarEvent('sidebar.removeAssignee', { let len;
id: firstSelectedId, let name;
}); let obj;
let showDivider;
if (term.length === 0) {
showDivider = 0;
if (firstUser) {
// Move current user to the front of the list
for (index = j = 0, len = users.length; j < len; index = (j += 1)) {
obj = users[index];
if (obj.username === firstUser) {
users.splice(index, 1);
users.unshift(obj);
break;
}
} }
} }
}; if (showNullUser) {
showDivider += 1;
const getMultiSelectDropdownTitle = function(selectedUser, isSelected) { users.unshift({
const selectedUsers = getSelected() beforeDivider: true,
.filter(u => u !== 0); name: 'Unassigned',
id: 0
const firstUser = getSelectedUserInputs() });
.map((index, input) => ({ }
name: input.dataset.meta, if (showAnyUser) {
value: parseInt(input.value, 10), showDivider += 1;
})) name = showAnyUser;
.filter(u => u.id !== 0) if (name === true) {
.get(0); name = 'Any User';
}
if (selectedUsers.length === 0) { anyUser = {
return 'Unassigned'; beforeDivider: true,
} else if (selectedUsers.length === 1) { name: name,
return firstUser.name; id: null
} else if (isSelected) { };
const otherSelected = selectedUsers.filter(s => s !== selectedUser.id); users.unshift(anyUser);
return `${selectedUser.name} + ${otherSelected.length} more`;
} else {
return `${firstUser.name} + ${selectedUsers.length - 1} more`;
} }
};
$('.assign-to-me-link').on('click', (e) => {
e.preventDefault();
$(e.currentTarget).hide();
if ($dropdown.data('multiSelect')) {
assignYourself();
checkMaxSelect();
const currentUserInfo = $dropdown.data('currentUserInfo'); if (showDivider) {
$dropdown.find('.dropdown-toggle-text').text(getMultiSelectDropdownTitle(currentUserInfo)).removeClass('is-default'); users.splice(showDivider, 0, 'divider');
} else {
const $input = $(`input[name="${$dropdown.data('field-name')}"]`);
$input.val(gon.current_user_id);
selectedId = $input.val();
$dropdown.find('.dropdown-toggle-text').text(gon.current_user_fullname).removeClass('is-default');
} }
});
$block.on('click', '.js-assign-yourself', (e) => { if ($dropdown.hasClass('js-multiselect')) {
e.preventDefault(); const selected = getSelected().filter(i => i !== 0);
return assignTo(_this.currentUser.id);
});
assignTo = function(selected) { if (selected.length > 0) {
var data; if ($dropdown.data('dropdown-header')) {
data = {};
data[abilityName] = {};
data[abilityName].assignee_id = selected != null ? selected : null;
$loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown');
return $.ajax({
type: 'PUT',
dataType: 'json',
url: issueURL,
data: data
}).done(function(data) {
var user;
$dropdown.trigger('loaded.gl.dropdown');
$loading.fadeOut();
if (data.assignee) {
user = {
name: data.assignee.name,
username: data.assignee.username,
avatar: data.assignee.avatar_url
};
} else {
user = {
name: 'Unassigned',
username: '',
avatar: ''
};
}
$value.html(assigneeTemplate(user));
$collapsedSidebar.attr('title', user.name).tooltip('fixTitle');
return $collapsedSidebar.html(collapsedAssigneeTemplate(user));
});
};
collapsedAssigneeTemplate = _.template('<% if( avatar ) { %> <a class="author_link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>');
assigneeTemplate = _.template('<% if (username) { %> <a class="author_link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself"> No assignee - <a href="#" class="js-assign-yourself"> assign yourself </a> </span> <% } %>');
return $dropdown.glDropdown({
showMenuAbove: showMenuAbove,
data: function(term, callback) {
var isAuthorFilter;
isAuthorFilter = $('.js-author-search');
return _this.users(term, options, function(users) {
// GitLabDropdownFilter returns this.instance
// GitLabDropdownRemote returns this.options.instance
const glDropdown = this.instance || this.options.instance;
glDropdown.options.processData(term, users, callback);
}.bind(this));
},
processData: function(term, users, callback) {
let anyUser;
let index;
let j;
let len;
let name;
let obj;
let showDivider;
if (term.length === 0) {
showDivider = 0;
if (firstUser) {
// Move current user to the front of the list
for (index = j = 0, len = users.length; j < len; index = (j += 1)) {
obj = users[index];
if (obj.username === firstUser) {
users.splice(index, 1);
users.unshift(obj);
break;
}
}
}
if (showNullUser) {
showDivider += 1; showDivider += 1;
users.unshift({ users.splice(showDivider, 0, {
beforeDivider: true, header: $dropdown.data('dropdown-header'),
name: 'Unassigned',
id: 0
}); });
} }
if (showAnyUser) {
showDivider += 1;
name = showAnyUser;
if (name === true) {
name = 'Any User';
}
anyUser = {
beforeDivider: true,
name: name,
id: null
};
users.unshift(anyUser);
}
if (showDivider) { const selectedUsers = users
users.splice(showDivider, 0, 'divider'); .filter(u => selected.indexOf(u.id) !== -1)
} .sort((a, b) => a.name > b.name);
if ($dropdown.hasClass('js-multiselect')) { users = users.filter(u => selected.indexOf(u.id) === -1);
const selected = getSelected().filter(i => i !== 0);
if (selected.length > 0) { selectedUsers.forEach((selectedUser) => {
if ($dropdown.data('dropdown-header')) { showDivider += 1;
showDivider += 1; users.splice(showDivider, 0, selectedUser);
users.splice(showDivider, 0, { });
header: $dropdown.data('dropdown-header'),
});
}
const selectedUsers = users
.filter(u => selected.indexOf(u.id) !== -1)
.sort((a, b) => a.name > b.name);
users = users.filter(u => selected.indexOf(u.id) === -1); users.splice(showDivider + 1, 0, 'divider');
}
}
}
selectedUsers.forEach((selectedUser) => { callback(users);
showDivider += 1; if (showMenuAbove) {
users.splice(showDivider, 0, selectedUser); $dropdown.data('glDropdown').positionMenuAbove();
}); }
},
filterable: true,
filterRemote: true,
search: {
fields: ['name', 'username']
},
selectable: true,
fieldName: $dropdown.data('field-name'),
toggleLabel: function(selected, el, glDropdown) {
const inputValue = glDropdown.filterInput.val();
if (this.multiSelect && inputValue === '') {
// Remove non-users from the fullData array
const users = glDropdown.filteredFullData();
const callback = glDropdown.parseData.bind(glDropdown);
// Update the data model
this.processData(inputValue, users, callback);
}
users.splice(showDivider + 1, 0, 'divider'); if (this.multiSelect) {
} return getMultiSelectDropdownTitle(selected, $(el).hasClass('is-active'));
} }
}
callback(users); if (selected && 'id' in selected && $(el).hasClass('is-active')) {
if (showMenuAbove) { $dropdown.find('.dropdown-toggle-text').removeClass('is-default');
$dropdown.data('glDropdown').positionMenuAbove(); if (selected.text) {
} return selected.text;
}, } else {
filterable: true, return selected.name;
filterRemote: true, }
search: { } else {
fields: ['name', 'username'] $dropdown.find('.dropdown-toggle-text').addClass('is-default');
}, return defaultLabel;
selectable: true, }
fieldName: $dropdown.data('field-name'), },
toggleLabel: function(selected, el, glDropdown) { defaultLabel: defaultLabel,
const inputValue = glDropdown.filterInput.val(); hidden: function(e) {
if ($dropdown.hasClass('js-multiselect')) {
if (this.multiSelect && inputValue === '') { emitSidebarEvent('sidebar.saveAssignees');
// Remove non-users from the fullData array }
const users = glDropdown.filteredFullData();
const callback = glDropdown.parseData.bind(glDropdown);
// Update the data model
this.processData(inputValue, users, callback);
}
if (this.multiSelect) { if (!$dropdown.data('always-show-selectbox')) {
return getMultiSelectDropdownTitle(selected, $(el).hasClass('is-active')); $selectbox.hide();
}
if (selected && 'id' in selected && $(el).hasClass('is-active')) { // Recalculate where .value is because vue might have changed it
$dropdown.find('.dropdown-toggle-text').removeClass('is-default'); $block = $selectbox.closest('.block');
if (selected.text) { $value = $block.find('.value');
return selected.text; // display:block overrides the hide-collapse rule
} else { $value.css('display', '');
return selected.name; }
} },
} else { multiSelect: $dropdown.hasClass('js-multiselect'),
$dropdown.find('.dropdown-toggle-text').addClass('is-default'); inputMeta: $dropdown.data('input-meta'),
return defaultLabel; clicked: function(options) {
} const { $el, e, isMarking } = options;
}, const user = options.selectedObj;
defaultLabel: defaultLabel,
hidden: function(e) { if ($dropdown.hasClass('js-multiselect')) {
if ($dropdown.hasClass('js-multiselect')) { const isActive = $el.hasClass('is-active');
emitSidebarEvent('sidebar.saveAssignees'); const previouslySelected = $dropdown.closest('.selectbox')
} .find("input[name='" + ($dropdown.data('field-name')) + "'][value!=0]");
// Enables support for limiting the number of users selected
// Automatically removes the first on the list if more users are selected
checkMaxSelect();
if (user.beforeDivider && user.name.toLowerCase() === 'unassigned') {
// Unassigned selected
previouslySelected.each((index, element) => {
const id = parseInt(element.value, 10);
element.remove();
});
emitSidebarEvent('sidebar.removeAllAssignees');
} else if (isActive) {
// user selected
emitSidebarEvent('sidebar.addAssignee', user);
if (!$dropdown.data('always-show-selectbox')) { // Remove unassigned selection (if it was previously selected)
$selectbox.hide(); const unassignedSelected = $dropdown.closest('.selectbox')
.find("input[name='" + ($dropdown.data('field-name')) + "'][value=0]");
// Recalculate where .value is because vue might have changed it if (unassignedSelected) {
$block = $selectbox.closest('.block'); unassignedSelected.remove();
$value = $block.find('.value'); }
// display:block overrides the hide-collapse rule } else {
$value.css('display', ''); if (previouslySelected.length === 0) {
// Select unassigned because there is no more selected users
this.addInput($dropdown.data('field-name'), 0, {});
} }
},
multiSelect: $dropdown.hasClass('js-multiselect'),
inputMeta: $dropdown.data('input-meta'),
clicked: function(options) {
const { $el, e, isMarking } = options;
const user = options.selectedObj;
if ($dropdown.hasClass('js-multiselect')) {
const isActive = $el.hasClass('is-active');
const previouslySelected = $dropdown.closest('.selectbox')
.find("input[name='" + ($dropdown.data('field-name')) + "'][value!=0]");
// Enables support for limiting the number of users selected
// Automatically removes the first on the list if more users are selected
checkMaxSelect();
if (user.beforeDivider && user.name.toLowerCase() === 'unassigned') {
// Unassigned selected
previouslySelected.each((index, element) => {
const id = parseInt(element.value, 10);
element.remove();
});
emitSidebarEvent('sidebar.removeAllAssignees');
} else if (isActive) {
// user selected
emitSidebarEvent('sidebar.addAssignee', user);
// Remove unassigned selection (if it was previously selected) // User unselected
const unassignedSelected = $dropdown.closest('.selectbox') emitSidebarEvent('sidebar.removeAssignee', user);
.find("input[name='" + ($dropdown.data('field-name')) + "'][value=0]"); }
if (unassignedSelected) { if (getSelected().find(u => u === gon.current_user_id)) {
unassignedSelected.remove(); $('.assign-to-me-link').hide();
} } else {
} else { $('.assign-to-me-link').show();
if (previouslySelected.length === 0) { }
// Select unassigned because there is no more selected users }
this.addInput($dropdown.data('field-name'), 0, {});
}
// User unselected var isIssueIndex, isMRIndex, page, selected;
emitSidebarEvent('sidebar.removeAssignee', user); page = $('body').data('page');
} isIssueIndex = page === 'projects:issues:index';
isMRIndex = (page === page && page === 'projects:merge_requests:index');
if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) {
e.preventDefault();
if (getSelected().find(u => u === gon.current_user_id)) { const isSelecting = (user.id !== selectedId);
$('.assign-to-me-link').hide(); selectedId = isSelecting ? user.id : selectedIdDefault;
} else {
$('.assign-to-me-link').show();
}
}
var isIssueIndex, isMRIndex, page, selected; if (selectedId === gon.current_user_id) {
page = $('body').data('page'); $('.assign-to-me-link').hide();
isIssueIndex = page === 'projects:issues:index'; } else {
isMRIndex = (page === page && page === 'projects:merge_requests:index'); $('.assign-to-me-link').show();
if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) { }
e.preventDefault(); return;
}
if ($el.closest('.add-issues-modal').length) {
gl.issueBoards.ModalStore.store.filter[$dropdown.data('field-name')] = user.id;
} else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
return Issuable.filterResults($dropdown.closest('form'));
} else if ($dropdown.hasClass('js-filter-submit')) {
return $dropdown.closest('form').submit();
} else if (!$dropdown.hasClass('js-multiselect')) {
selected = $dropdown.closest('.selectbox').find("input[name='" + ($dropdown.data('field-name')) + "']").val();
return assignTo(selected);
}
},
id: function (user) {
return user.id;
},
opened: function(e) {
const $el = $(e.currentTarget);
if ($dropdown.hasClass('js-issue-board-sidebar')) {
selectedId = parseInt($dropdown[0].dataset.selected, 10) || selectedIdDefault;
}
$el.find('.is-active').removeClass('is-active');
const isSelecting = (user.id !== selectedId); function highlightSelected(id) {
selectedId = isSelecting ? user.id : selectedIdDefault; $el.find(`li[data-user-id="${id}"] .dropdown-menu-user-link`).addClass('is-active');
}
if (selectedId === gon.current_user_id) { if ($selectbox[0]) {
$('.assign-to-me-link').hide(); getSelected().forEach(selectedId => highlightSelected(selectedId));
} else { } else {
$('.assign-to-me-link').show(); highlightSelected(selectedId);
} }
return; },
} updateLabel: $dropdown.data('dropdown-title'),
if ($el.closest('.add-issues-modal').length) { renderRow: function(user) {
gl.issueBoards.ModalStore.store.filter[$dropdown.data('field-name')] = user.id; var avatar, img, listClosingTags, listWithName, listWithUserName, username;
} else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { username = user.username ? "@" + user.username : "";
return Issuable.filterResults($dropdown.closest('form')); avatar = user.avatar_url ? user.avatar_url : false;
} else if ($dropdown.hasClass('js-filter-submit')) {
return $dropdown.closest('form').submit();
} else if (!$dropdown.hasClass('js-multiselect')) {
selected = $dropdown.closest('.selectbox').find("input[name='" + ($dropdown.data('field-name')) + "']").val();
return assignTo(selected);
}
},
id: function (user) {
return user.id;
},
opened: function(e) {
const $el = $(e.currentTarget);
if ($dropdown.hasClass('js-issue-board-sidebar')) {
selectedId = parseInt($dropdown[0].dataset.selected, 10) || selectedIdDefault;
}
$el.find('.is-active').removeClass('is-active');
function highlightSelected(id) { let selected = user.id === parseInt(selectedId, 10);
$el.find(`li[data-user-id="${id}"] .dropdown-menu-user-link`).addClass('is-active');
}
if ($selectbox[0]) { if (this.multiSelect) {
getSelected().forEach(selectedId => highlightSelected(selectedId)); const fieldName = this.fieldName;
} else { const field = $dropdown.closest('.selectbox').find("input[name='" + fieldName + "'][value='" + user.id + "']");
highlightSelected(selectedId);
}
},
updateLabel: $dropdown.data('dropdown-title'),
renderRow: function(user) {
var avatar, img, listClosingTags, listWithName, listWithUserName, username;
username = user.username ? "@" + user.username : "";
avatar = user.avatar_url ? user.avatar_url : false;
let selected = user.id === parseInt(selectedId, 10); if (field.length) {
selected = true;
}
}
if (this.multiSelect) { img = "";
const fieldName = this.fieldName; if (user.beforeDivider != null) {
const field = $dropdown.closest('.selectbox').find("input[name='" + fieldName + "'][value='" + user.id + "']"); `<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${user.name}</a></li>`;
} else {
if (avatar) {
img = "<img src='" + avatar + "' class='avatar avatar-inline' width='32' />";
}
}
if (field.length) { return `
selected = true; <li data-user-id=${user.id}>
<a href='#' class='dropdown-menu-user-link ${selected === true ? 'is-active' : ''}'>
${img}
<strong class='dropdown-menu-user-full-name'>
${user.name}
</strong>
${username ? `<span class='dropdown-menu-user-username'>${username}</span>` : ''}
</a>
</li>
`;
}
});
};
})(this));
$('.ajax-users-select').each((function(_this) {
return function(i, select) {
var firstUser, showAnyUser, showEmailUser, showNullUser;
var options = {};
options.skipLdap = $(select).hasClass('skip_ldap');
options.projectId = $(select).data('project-id');
options.groupId = $(select).data('group-id');
options.showCurrentUser = $(select).data('current-user');
options.pushCodeToProtectedBranches = $(select).data('push-code-to-protected-branches');
options.authorId = $(select).data('author-id');
options.skipUsers = $(select).data('skip-users');
showNullUser = $(select).data('null-user');
showAnyUser = $(select).data('any-user');
showEmailUser = $(select).data('email-user');
firstUser = $(select).data('first-user');
return $(select).select2({
placeholder: "Search for a user",
multiple: $(select).hasClass('multiselect'),
minimumInputLength: 0,
query: function(query) {
return _this.users(query.term, options, function(users) {
var anyUser, data, emailUser, index, j, len, name, nullUser, obj, ref;
data = {
results: users
};
if (query.term.length === 0) {
if (firstUser) {
// Move current user to the front of the list
ref = data.results;
for (index = j = 0, len = ref.length; j < len; index = (j += 1)) {
obj = ref[index];
if (obj.username === firstUser) {
data.results.splice(index, 1);
data.results.unshift(obj);
break;
}
} }
} }
if (showNullUser) {
img = ""; nullUser = {
if (user.beforeDivider != null) { name: 'Unassigned',
`<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${user.name}</a></li>`; id: 0
} else { };
if (avatar) { data.results.unshift(nullUser);
img = "<img src='" + avatar + "' class='avatar avatar-inline' width='32' />"; }
if (showAnyUser) {
name = showAnyUser;
if (name === true) {
name = 'Any User';
} }
anyUser = {
name: name,
id: null
};
data.results.unshift(anyUser);
} }
return `
<li data-user-id=${user.id}>
<a href='#' class='dropdown-menu-user-link ${selected === true ? 'is-active' : ''}'>
${img}
<strong class='dropdown-menu-user-full-name'>
${user.name}
</strong>
${username ? `<span class='dropdown-menu-user-username'>${username}</span>` : ''}
</a>
</li>
`;
} }
}); if (showEmailUser && data.results.length === 0 && query.term.match(/^[^@]+@[^@]+$/)) {
}; var trimmed = query.term.trim();
})(this)); emailUser = {
$('.ajax-users-select').each((function(_this) { name: "Invite \"" + query.term + "\"",
return function(i, select) { username: trimmed,
var firstUser, showAnyUser, showEmailUser, showNullUser; id: trimmed
var options = {}; };
options.skipLdap = $(select).hasClass('skip_ldap'); data.results.unshift(emailUser);
options.projectId = $(select).data('project-id');
options.groupId = $(select).data('group-id');
options.showCurrentUser = $(select).data('current-user');
options.pushCodeToProtectedBranches = $(select).data('push-code-to-protected-branches');
options.authorId = $(select).data('author-id');
options.skipUsers = $(select).data('skip-users');
showNullUser = $(select).data('null-user');
showAnyUser = $(select).data('any-user');
showEmailUser = $(select).data('email-user');
firstUser = $(select).data('first-user');
return $(select).select2({
placeholder: "Search for a user",
multiple: $(select).hasClass('multiselect'),
minimumInputLength: 0,
query: function(query) {
return _this.users(query.term, options, function(users) {
var anyUser, data, emailUser, index, j, len, name, nullUser, obj, ref;
data = {
results: users
};
if (query.term.length === 0) {
if (firstUser) {
// Move current user to the front of the list
ref = data.results;
for (index = j = 0, len = ref.length; j < len; index = (j += 1)) {
obj = ref[index];
if (obj.username === firstUser) {
data.results.splice(index, 1);
data.results.unshift(obj);
break;
}
}
}
if (showNullUser) {
nullUser = {
name: 'Unassigned',
id: 0
};
data.results.unshift(nullUser);
}
if (showAnyUser) {
name = showAnyUser;
if (name === true) {
name = 'Any User';
}
anyUser = {
name: name,
id: null
};
data.results.unshift(anyUser);
}
}
if (showEmailUser && data.results.length === 0 && query.term.match(/^[^@]+@[^@]+$/)) {
var trimmed = query.term.trim();
emailUser = {
name: "Invite \"" + query.term + "\"",
username: trimmed,
id: trimmed
};
data.results.unshift(emailUser);
}
return query.callback(data);
});
},
initSelection: function() {
var args;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
return _this.initSelection.apply(_this, args);
},
formatResult: function() {
var args;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
return _this.formatResult.apply(_this, args);
},
formatSelection: function() {
var args;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
return _this.formatSelection.apply(_this, args);
},
dropdownCssClass: "ajax-users-dropdown",
// we do not want to escape markup since we are displaying html in results
escapeMarkup: function(m) {
return m;
} }
return query.callback(data);
}); });
};
})(this));
}
UsersSelect.prototype.initSelection = function(element, callback) {
var id, nullUser;
id = $(element).val();
if (id === "0") {
nullUser = {
name: 'Unassigned'
};
return callback(nullUser);
} else if (id !== "") {
return this.user(id, callback);
}
};
UsersSelect.prototype.formatResult = function(user) {
var avatar;
if (user.avatar_url) {
avatar = user.avatar_url;
} else {
avatar = gon.default_avatar_url;
}
return "<div class='user-result " + (!user.username ? 'no-username' : void 0) + "'> <div class='user-image'><img class='avatar s24' src='" + avatar + "'></div> <div class='user-name'>" + user.name + "</div> <div class='user-username'>" + (user.username || "") + "</div> </div>";
};
UsersSelect.prototype.formatSelection = function(user) {
return user.name;
};
UsersSelect.prototype.user = function(user_id, callback) {
if (!/^\d+$/.test(user_id)) {
return false;
}
var url;
url = this.buildUrl(this.userPath);
url = url.replace(':id', user_id);
return $.ajax({
url: url,
dataType: "json"
}).done(function(user) {
return callback(user);
});
};
// Return users list. Filtered by query
// Only active users retrieved
UsersSelect.prototype.users = function(query, options, callback) {
var url;
url = this.buildUrl(this.usersPath);
return $.ajax({
url: url,
data: {
search: query,
per_page: 20,
active: true,
project_id: options.projectId || null,
group_id: options.groupId || null,
skip_ldap: options.skipLdap || null,
todo_filter: options.todoFilter || null,
todo_state_filter: options.todoStateFilter || null,
current_user: options.showCurrentUser || null,
push_code_to_protected_branches: options.pushCodeToProtectedBranches || null,
author_id: options.authorId || null,
skip_users: options.skipUsers || null
}, },
dataType: "json" initSelection: function() {
}).done(function(users) { var args;
return callback(users); args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
return _this.initSelection.apply(_this, args);
},
formatResult: function() {
var args;
args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
return _this.formatResult.apply(_this, args);
},
formatSelection: function() {
var args;
args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
return _this.formatSelection.apply(_this, args);
},
dropdownCssClass: "ajax-users-dropdown",
// we do not want to escape markup since we are displaying html in results
escapeMarkup: function(m) {
return m;
}
}); });
}; };
})(this));
UsersSelect.prototype.buildUrl = function(url) { }
if (gon.relative_url_root != null) {
url = gon.relative_url_root.replace(/\/$/, '') + url; UsersSelect.prototype.initSelection = function(element, callback) {
} var id, nullUser;
return url; id = $(element).val();
if (id === "0") {
nullUser = {
name: 'Unassigned'
}; };
return callback(nullUser);
return UsersSelect; } else if (id !== "") {
})(); return this.user(id, callback);
}).call(window); }
};
UsersSelect.prototype.formatResult = function(user) {
var avatar;
if (user.avatar_url) {
avatar = user.avatar_url;
} else {
avatar = gon.default_avatar_url;
}
return "<div class='user-result " + (!user.username ? 'no-username' : void 0) + "'> <div class='user-image'><img class='avatar s24' src='" + avatar + "'></div> <div class='user-name'>" + user.name + "</div> <div class='user-username'>" + (user.username || "") + "</div> </div>";
};
UsersSelect.prototype.formatSelection = function(user) {
return user.name;
};
UsersSelect.prototype.user = function(user_id, callback) {
if (!/^\d+$/.test(user_id)) {
return false;
}
var url;
url = this.buildUrl(this.userPath);
url = url.replace(':id', user_id);
return $.ajax({
url: url,
dataType: "json"
}).done(function(user) {
return callback(user);
});
};
// Return users list. Filtered by query
// Only active users retrieved
UsersSelect.prototype.users = function(query, options, callback) {
var url;
url = this.buildUrl(this.usersPath);
return $.ajax({
url: url,
data: {
search: query,
per_page: 20,
active: true,
project_id: options.projectId || null,
group_id: options.groupId || null,
skip_ldap: options.skipLdap || null,
todo_filter: options.todoFilter || null,
todo_state_filter: options.todoStateFilter || null,
current_user: options.showCurrentUser || null,
push_code_to_protected_branches: options.pushCodeToProtectedBranches || null,
author_id: options.authorId || null,
skip_users: options.skipUsers || null
},
dataType: "json"
}).done(function(users) {
return callback(users);
});
};
UsersSelect.prototype.buildUrl = function(url) {
if (gon.relative_url_root != null) {
url = gon.relative_url_root.replace(/\/$/, '') + url;
}
return url;
};
export default UsersSelect;
...@@ -46,6 +46,3 @@ ...@@ -46,6 +46,3 @@
.form-actions .form-actions
= submit_tag 'Continue to the next step', class: 'btn btn-create' = submit_tag 'Continue to the next step', class: 'btn btn-create'
:javascript
new UsersSelect();
...@@ -71,7 +71,6 @@ ...@@ -71,7 +71,6 @@
= render 'shared/labels_row', labels: @labels = render 'shared/labels_row', labels: @labels
:javascript :javascript
new UsersSelect();
new LabelsSelect(); new LabelsSelect();
new MilestoneSelect(); new MilestoneSelect();
new IssueStatusSelect(); new IssueStatusSelect();
......
...@@ -150,7 +150,6 @@ ...@@ -150,7 +150,6 @@
- unless type === :boards_modal - unless type === :boards_modal
:javascript :javascript
new UsersSelect();
new LabelsSelect(); new LabelsSelect();
new MilestoneSelect(); new MilestoneSelect();
new IssueStatusSelect(); new IssueStatusSelect();
......
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