feat: #5272, allow changing user groups from manage users page

v1.18.x
Barış Soner Uşaklı 5 years ago
parent ff8dfa049d
commit 05c9fe2735

@ -15,6 +15,8 @@
"delete": "Delete User(s)", "delete": "Delete User(s)",
"purge": "Delete User(s) and Content", "purge": "Delete User(s) and Content",
"download-csv": "Download CSV", "download-csv": "Download CSV",
"manage-groups": "Manage Groups",
"add-group": "Add Group",
"invite": "Invite", "invite": "Invite",
"new": "New User", "new": "New User",

@ -1,57 +1,19 @@
.manage-users { .manage-users {
min-height: 500px; min-height: 500px;
.search {
#users-container { .form-control {
border: 1px solid #eee; width: 100%;
padding: 0px 20px 20px;
.users-box {
display: inline-block;
margin-top: 20px;
text-align: center;
vertical-align: top;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
height: auto;
max-width: 145px;
min-width: 145px;
padding: 1rem;
img, .user-icon {
.user-icon-style(80px, 4rem);
}
a {
margin-bottom:5px;
font-size: 12px;
}
.user-image {
position: relative;
.labels {
position: absolute;
bottom: 0px;
width: 100%;
span {
width: 100%;
opacity: 0.9;
font-size: 10px;
display: block;
border-radius: 0;
}
}
}
} }
}
}
.ui-selected { .page-admin-users {
background: lighten(@brand-success, 25%); .group-card {
} margin: 2px;
padding: 2px;
}
.ui-selecting { .remove-group-icon {
background: lighten(@brand-success, 40%); margin-left: 5px;
}
} }
} }

@ -1,13 +1,12 @@
'use strict'; 'use strict';
define('admin/manage/users', ['translator', 'benchpress', 'autocomplete'], function (translator, Benchpress, autocomplete) {
define('admin/manage/users', ['translator', 'benchpress'], function (translator, Benchpress) {
var Users = {}; var Users = {};
Users.init = function () { Users.init = function () {
var navPills = $('.nav-pills li'); var navPills = $('.nav-pills li');
var pathname = window.location.pathname; var pathname = window.location.pathname;
if (!navPills.find('a[href^="' + pathname + '"]').length) { if (!navPills.find('a[href^="' + pathname + '"]').length || pathname === config.relative_path + '/admin/manage/users') {
pathname = config.relative_path + '/admin/manage/users/latest'; pathname = config.relative_path + '/admin/manage/users/latest';
} }
navPills.removeClass('active').find('a[href^="' + pathname + '"]').parent().addClass('active'); navPills.removeClass('active').find('a[href^="' + pathname + '"]').parent().addClass('active');
@ -59,11 +58,56 @@ define('admin/manage/users', ['translator', 'benchpress'], function (translator,
} }
$('[component="user/select/all"]').on('click', function () { $('[component="user/select/all"]').on('click', function () {
if ($(this).is(':checked')) { $('.users-table [component="user/select/single"]').prop('checked', $(this).is(':checked'));
$('.users-table [component="user/select/single"]').prop('checked', true); });
} else {
$('.users-table [component="user/select/single"]').prop('checked', false); $('.manage-groups').on('click', function () {
var uids = getSelectedUids();
if (!uids.length) {
app.alertError('[[error:no-users-selected]]');
return false;
} }
socket.emit('admin.user.loadGroups', uids, function (err, data) {
if (err) {
return app.alertError(err);
}
Benchpress.parse('admin/partials/manage_user_groups', data, function (html) {
var modal = bootbox.dialog({
message: utils.escapeHTML(html),
title: '[[admin/manage/users:manage-groups]]',
onEscape: true,
});
modal.on('shown.bs.modal', function () {
autocomplete.group(modal.find('.group-search'), function (ev, ui) {
var uid = $(ev.target).attr('data-uid');
socket.emit('admin.groups.join', { uid: uid, groupName: ui.item.value }, function (err) {
if (err) {
return app.alertError(err);
}
ui.item.group.nameEscaped = translator.escape(ui.item.group.displayName);
app.parseAndTranslate('admin/partials/manage_user_groups', { users: [{ groups: [ui.item.group] }] }, function (html) {
$('[data-uid=' + uid + '] .group-area').append(html.find('.group-area').html());
});
});
});
});
modal.on('click', '.group-area a', function () {
modal.modal('hide');
});
modal.on('click', '.remove-group-icon', function () {
var groupCard = $(this).parents('[data-group-name]');
var groupName = groupCard.attr('data-group-name');
var uid = $(this).parents('[data-uid]').attr('data-uid');
socket.emit('admin.groups.leave', { uid: uid, groupName: groupName }, function (err) {
if (err) {
return app.alertError(err);
}
groupCard.remove();
});
return false;
});
});
});
}); });
$('.ban-user').on('click', function () { $('.ban-user').on('click', function () {
@ -321,8 +365,8 @@ define('admin/manage/users', ['translator', 'benchpress'], function (translator,
Benchpress.parse('admin/manage/users', 'users', data, function (html) { Benchpress.parse('admin/manage/users', 'users', data, function (html) {
translator.translate(html, function (html) { translator.translate(html, function (html) {
html = $(html); html = $(html);
$('.users-table tr').not(':first').remove(); $('.users-table tbody tr').remove();
$('.users-table tr').first().after(html); $('.users-table tbody').append(html);
html.find('.timeago').timeago(); html.find('.timeago').timeago();
$('.fa-spinner').addClass('hidden'); $('.fa-spinner').addClass('hidden');

@ -55,7 +55,12 @@ define('autocomplete', function () {
app.loadJQueryUI(function () { app.loadJQueryUI(function () {
input.autocomplete({ input.autocomplete({
delay: 200, delay: 200,
select: onselect, open: function () {
$(this).autocomplete('widget').css('z-index', 100005);
},
select: function (event, ui) {
handleOnSelect(input, onselect, event, ui);
},
source: function (request, response) { source: function (request, response) {
socket.emit('groups.search', { socket.emit('groups.search', {
query: request.term, query: request.term,
@ -63,16 +68,12 @@ define('autocomplete', function () {
if (err) { if (err) {
return app.alertError(err.message); return app.alertError(err.message);
} }
if (results && results.length) { if (results && results.length) {
var names = results.map(function (group) { var names = results.map(function (group) {
return group && { return group && {
label: group.name, label: group.name,
value: group.name, value: group.name,
group: { group: group,
name: group.name,
slug: group.slug,
},
}; };
}); });
response(names); response(names);

@ -13,7 +13,7 @@ module.exports = function (Groups) {
if (!options.hideEphemeralGroups) { if (!options.hideEphemeralGroups) {
groupNames = Groups.ephemeralGroups.concat(groupNames); groupNames = Groups.ephemeralGroups.concat(groupNames);
} }
groupNames = groupNames.filter(name => name.toLowerCase().includes(query) && name !== 'administrators' && !Groups.isPrivilegeGroup(name)); groupNames = groupNames.filter(name => name.toLowerCase().includes(query) && !Groups.isPrivilegeGroup(name));
groupNames = groupNames.slice(0, 100); groupNames = groupNames.slice(0, 100);
let groupsData; let groupsData;

@ -9,6 +9,7 @@ const user = require('../../user');
const events = require('../../events'); const events = require('../../events');
const meta = require('../../meta'); const meta = require('../../meta');
const plugins = require('../../plugins'); const plugins = require('../../plugins');
const translator = require('../../translator');
const User = module.exports; const User = module.exports;
@ -190,3 +191,17 @@ User.search = async function (socket, data) {
User.restartJobs = async function () { User.restartJobs = async function () {
user.startJobs(); user.startJobs();
}; };
User.loadGroups = async function (socket, uids) {
const [userData, groupData] = await Promise.all([
user.getUsersData(uids),
groups.getUserGroupsFromSet('groups:createtime', uids),
]);
userData.forEach((data, index) => {
data.groups = groupData[index].filter(group => !groups.isPrivilegeGroup(group.name));
data.groups.forEach((group) => {
group.nameEscaped = translator.escape(group.displayName);
});
});
return { users: userData };
};

@ -1,127 +1,127 @@
<div class="row manage-users"> <div class="row manage-users">
<div class="col-lg-12"> <div class="col-lg-12">
<div class="panel panel-default"> <div class="clearfix">
<div class="panel-heading"><i class="fa fa-user"></i> [[admin/manage/users:users]]</div> <form class="form-inline pull-right">
<div class="panel-body"> <button id="createUser" class="btn btn-primary">[[admin/manage/users:new]]</button>
<!-- IF inviteOnly -->
<div class="clearfix"> <button component="user/invite" class="btn btn-success"><i class="fa fa-users"></i> [[admin/manage/users:invite]]</button>
<div class="btn-group pull-right"> <!-- ENDIF inviteOnly -->
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown" type="button">[[admin/manage/users:edit]] <span class="caret"></span></button> <a target="_blank" href="{config.relative_path}/api/admin/users/csv" class="btn btn-primary">[[admin/manage/users:download-csv]]</a>
<ul class="dropdown-menu"> <div class="btn-group">
<li><a href="#" class="validate-email"><i class="fa fa-fw fa-check"></i> [[admin/manage/users:validate-email]]</a></li> <button class="btn btn-default dropdown-toggle" data-toggle="dropdown" type="button">[[admin/manage/users:edit]] <span class="caret"></span></button>
<li><a href="#" class="send-validation-email"><i class="fa fa-fw fa-mail-forward"></i> [[admin/manage/users:send-validation-email]]</a></li> <ul class="dropdown-menu dropdown-menu-right">
<li><a href="#" class="password-reset-email"><i class="fa fa-fw fa-key"></i> [[admin/manage/users:password-reset-email]]</a></li> <li><a href="#" class="validate-email"><i class="fa fa-fw fa-check"></i> [[admin/manage/users:validate-email]]</a></li>
<li><a href="#" class="force-password-reset"><i class="fa fa-fw fa-unlock-alt"></i> [[admin/manage/users:force-password-reset]]</a></li> <li><a href="#" class="send-validation-email"><i class="fa fa-fw fa-mail-forward"></i> [[admin/manage/users:send-validation-email]]</a></li>
<li class="divider"></li> <li><a href="#" class="password-reset-email"><i class="fa fa-fw fa-key"></i> [[admin/manage/users:password-reset-email]]</a></li>
<li><a href="#" class="ban-user"><i class="fa fa-fw fa-gavel"></i> [[admin/manage/users:ban]]</a></li> <li><a href="#" class="force-password-reset"><i class="fa fa-fw fa-unlock-alt"></i> [[admin/manage/users:force-password-reset]]</a></li>
<li><a href="#" class="ban-user-temporary"><i class="fa fa-fw fa-clock-o"></i>[[admin/manage/users:temp-ban]]</a></li> <li><a href="#" class="manage-groups"><i class="fa fa-fw fa-users"></i> [[admin/manage/users:manage-groups]]</a></li>
<li><a href="#" class="unban-user"><i class="fa fa-fw fa-comment-o"></i> [[admin/manage/users:unban]]</a></li> <li class="divider"></li>
<li><a href="#" class="reset-lockout"><i class="fa fa-fw fa-unlock"></i> [[admin/manage/users:reset-lockout]]</a></li> <li><a href="#" class="ban-user"><i class="fa fa-fw fa-gavel"></i> [[admin/manage/users:ban]]</a></li>
<li class="divider"></li> <li><a href="#" class="ban-user-temporary"><i class="fa fa-fw fa-clock-o"></i>[[admin/manage/users:temp-ban]]</a></li>
<li><a href="#" class="delete-user"><i class="fa fa-fw fa-trash-o"></i> [[admin/manage/users:delete]]</a></li> <li><a href="#" class="unban-user"><i class="fa fa-fw fa-comment-o"></i> [[admin/manage/users:unban]]</a></li>
<li><a href="#" class="delete-user-and-content"><i class="fa fa-fw fa-trash-o"></i> [[admin/manage/users:purge]]</a></li> <li><a href="#" class="reset-lockout"><i class="fa fa-fw fa-unlock"></i> [[admin/manage/users:reset-lockout]]</a></li>
</ul> <li class="divider"></li>
</div> <li><a href="#" class="delete-user"><i class="fa fa-fw fa-trash-o"></i> [[admin/manage/users:delete]]</a></li>
<li><a href="#" class="delete-user-and-content"><i class="fa fa-fw fa-trash-o"></i> [[admin/manage/users:purge]]</a></li>
<a target="_blank" href="{config.relative_path}/api/admin/users/csv" class="btn btn-primary pull-right">[[admin/manage/users:download-csv]]</a> </ul>
<!-- IF inviteOnly -->
<button component="user/invite" class="btn btn-success pull-right"><i class="fa fa-users"></i> [[admin/manage/users:invite]]</button>
<!-- ENDIF inviteOnly -->
<button id="createUser" class="btn btn-primary pull-right">[[admin/manage/users:new]]</button>
</div> </div>
</form>
<ul class="nav nav-pills"> </div>
<li><a href='{config.relative_path}/admin/manage/users/latest?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.latest]]</a></li> <hr/>
<li><a href='{config.relative_path}/admin/manage/users/not-validated?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.unvalidated]]</a></li> <ul class="nav nav-pills">
<li><a href='{config.relative_path}/admin/manage/users/no-posts?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.no-posts]]</a></li> <li><a href='{config.relative_path}/admin/manage/users/latest?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.latest]]</a></li>
<li><a href='{config.relative_path}/admin/manage/users/top-posters?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.top-posters]]</a></li> <li><a href='{config.relative_path}/admin/manage/users/not-validated?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.unvalidated]]</a></li>
<li><a href='{config.relative_path}/admin/manage/users/most-reputation?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.top-rep]]</a></li> <li><a href='{config.relative_path}/admin/manage/users/no-posts?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.no-posts]]</a></li>
<li><a href='{config.relative_path}/admin/manage/users/inactive?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.inactive]]</a></li> <li><a href='{config.relative_path}/admin/manage/users/top-posters?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.top-posters]]</a></li>
<li><a href='{config.relative_path}/admin/manage/users/flagged?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.flagged]]</a></li> <li><a href='{config.relative_path}/admin/manage/users/most-reputation?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.top-rep]]</a></li>
<li><a href='{config.relative_path}/admin/manage/users/banned?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.banned]]</a></li> <li><a href='{config.relative_path}/admin/manage/users/inactive?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.inactive]]</a></li>
<li><a href='{config.relative_path}/admin/manage/users/search'>[[admin/manage/users:pills.search]]</a></li> <li><a href='{config.relative_path}/admin/manage/users/flagged?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.flagged]]</a></li>
<li class="pull-right"> <li><a href='{config.relative_path}/admin/manage/users/banned?resultsPerPage={resultsPerPage}'>[[admin/manage/users:pills.banned]]</a></li>
<form class="form-inline"> <li><a href='{config.relative_path}/admin/manage/users/search'>[[admin/manage/users:pills.search]]</a></li>
<select id="results-per-page" class="form-control"> <li class="pull-right">
<option value="50">[[admin/manage/users:50-per-page]]</option> <form class="form-inline">
<option value="100">[[admin/manage/users:100-per-page]]</option> <select id="results-per-page" class="form-control">
<option value="250">[[admin/manage/users:250-per-page]]</option> <option value="50">[[admin/manage/users:50-per-page]]</option>
<option value="500">[[admin/manage/users:500-per-page]]</option> <option value="100">[[admin/manage/users:100-per-page]]</option>
</select> <option value="250">[[admin/manage/users:250-per-page]]</option>
</form> <option value="500">[[admin/manage/users:500-per-page]]</option>
</li> </select>
</ul> </form>
</li>
</ul>
<br />
<br />
<div class="search {search_display}">
<div class="search {search_display}">
<form class="form-inline">
<div class="form-group">
<label>[[admin/manage/users:search.uid]]</label> <label>[[admin/manage/users:search.uid]]</label>
<input class="form-control" id="search-user-uid" data-search-type="uid" type="number" placeholder="[[admin/manage/users:search.uid-placeholder]]"/><br /> <input class="form-control" id="search-user-uid" data-search-type="uid" type="number" placeholder="[[admin/manage/users:search.uid-placeholder]]"/><br />
</div>
<div class="form-group">
<label>[[admin/manage/users:search.username]]</label> <label>[[admin/manage/users:search.username]]</label>
<input class="form-control" id="search-user-name" data-search-type="username" type="text" placeholder="[[admin/manage/users:search.username-placeholder]]"/><br /> <input class="form-control" id="search-user-name" data-search-type="username" type="text" placeholder="[[admin/manage/users:search.username-placeholder]]"/><br />
</div>
<div class="form-group">
<label>[[admin/manage/users:search.email]]</label> <label>[[admin/manage/users:search.email]]</label>
<input class="form-control" id="search-user-email" data-search-type="email" type="text" placeholder="[[admin/manage/users:search.email-placeholder]]"/><br /> <input class="form-control" id="search-user-email" data-search-type="email" type="text" placeholder="[[admin/manage/users:search.email-placeholder]]"/><br />
</div>
<div class="form-group">
<label>[[admin/manage/users:search.ip]]</label> <label>[[admin/manage/users:search.ip]]</label>
<input class="form-control" id="search-user-ip" data-search-type="ip" type="text" placeholder="[[admin/manage/users:search.ip-placeholder]]"/><br /> <input class="form-control" id="search-user-ip" data-search-type="ip" type="text" placeholder="[[admin/manage/users:search.ip-placeholder]]"/><br />
<i class="fa fa-spinner fa-spin hidden"></i>
<span id="user-notfound-notify" class="label label-danger hide">[[admin/manage/users:search.not-found]]</span><br/>
</div> </div>
</form>
<i class="fa fa-spinner fa-spin hidden"></i>
<span id="user-notfound-notify" class="label label-danger hide">[[admin/manage/users:search.not-found]]</span><br/>
</div>
<!-- IF inactive --> <!-- IF inactive -->
<a href="{config.relative_path}/admin/manage/users/inactive?months=3&resultsPerPage={resultsPerPage}" class="btn btn-default">[[admin/manage/users:inactive.3-months]]</a> <a href="{config.relative_path}/admin/manage/users/inactive?months=3&resultsPerPage={resultsPerPage}" class="btn btn-default">[[admin/manage/users:inactive.3-months]]</a>
<a href="{config.relative_path}/admin/manage/users/inactive?months=6&resultsPerPage={resultsPerPage}" class="btn btn-default">[[admin/manage/users:inactive.6-months]]</a> <a href="{config.relative_path}/admin/manage/users/inactive?months=6&resultsPerPage={resultsPerPage}" class="btn btn-default">[[admin/manage/users:inactive.6-months]]</a>
<a href="{config.relative_path}/admin/manage/users/inactive?months=12&resultsPerPage={resultsPerPage}" class="btn btn-default">[[admin/manage/users:inactive.12-months]]</a> <a href="{config.relative_path}/admin/manage/users/inactive?months=12&resultsPerPage={resultsPerPage}" class="btn btn-default">[[admin/manage/users:inactive.12-months]]</a>
<!-- ENDIF inactive --> <!-- ENDIF inactive -->
<div class="table-responsive">
<table class="table table-striped users-table">
<thead>
<tr>
<th><input component="user/select/all" type="checkbox"/></th>
<th class="text-right">[[admin/manage/users:users.uid]]</th>
<th>[[admin/manage/users:users.username]]</th>
<th>[[admin/manage/users:users.email]]</th>
<th class="text-right">[[admin/manage/users:users.postcount]]</th>
<th class="text-right">[[admin/manage/users:users.reputation]]</th>
<th class="text-right">[[admin/manage/users:users.flags]]</th>
<th>[[admin/manage/users:users.joined]]</th>
<th>[[admin/manage/users:users.last-online]]</th>
<th>[[admin/manage/users:users.banned]]</th>
</tr>
</thead>
<tbody>
<!-- BEGIN users -->
<tr class="user-row">
<th><input component="user/select/single" data-uid="{users.uid}" type="checkbox"/></th>
<td class="text-right">{users.uid}</td>
<td><i class="administrator fa fa-shield text-success<!-- IF !users.administrator --> hidden<!-- ENDIF !users.administrator -->"></i><a href="{config.relative_path}/user/{users.userslug}"> {users.username}</a></td>
<td>
<!-- IF config.requireEmailConfirmation -->
<i class="validated fa fa-check text-success<!-- IF !users.email:confirmed --> hidden<!-- ENDIF !users.email:confirmed -->" title="validated"></i>
<i class="notvalidated fa fa-times text-danger<!-- IF users.email:confirmed --> hidden<!-- ENDIF users.email:confirmed -->" title="not validated"></i>
<!-- ENDIF config.requireEmailConfirmation --> {users.email}</td>
<td class="text-right">{users.postcount}</td>
<td class="text-right">{users.reputation}</td>
<td class="text-right"><!-- IF users.flags -->{users.flags}<!-- ELSE -->0<!-- ENDIF users.flags --></td>
<td><span class="timeago" title="{users.joindateISO}"></span></td>
<td><span class="timeago" title="{users.lastonlineISO}"></span></td>
<td class="text-center"><i class="ban fa fa-gavel text-danger<!-- IF !users.banned --> hidden<!-- ENDIF !users.banned -->"></i></td>
</tr>
<!-- END users -->
</tbody>
</table>
</div>
<div class="table-responsive"> <!-- IMPORT partials/paginator.tpl -->
<table class="table table-striped users-table">
<thead>
<tr>
<th><input component="user/select/all" type="checkbox"/></th>
<th>[[admin/manage/users:users.uid]]</th>
<th>[[admin/manage/users:users.username]]</th>
<th>[[admin/manage/users:users.email]]</th>
<th class="text-right">[[admin/manage/users:users.postcount]]</th>
<th class="text-right">[[admin/manage/users:users.reputation]]</th>
<th class="text-right">[[admin/manage/users:users.flags]]</th>
<th>[[admin/manage/users:users.joined]]</th>
<th>[[admin/manage/users:users.last-online]]</th>
<th>[[admin/manage/users:users.banned]]</th>
</tr>
</thead>
<tbody>
<!-- BEGIN users -->
<tr class="user-row">
<th><input component="user/select/single" data-uid="{users.uid}" type="checkbox"/></th>
<td class="text-right">{users.uid}</td>
<td><i class="administrator fa fa-shield text-success<!-- IF !users.administrator --> hidden<!-- ENDIF !users.administrator -->"></i><a href="{config.relative_path}/user/{users.userslug}"> {users.username}</a></td>
<td>
<!-- IF config.requireEmailConfirmation -->
<i class="validated fa fa-check text-success<!-- IF !users.email:confirmed --> hidden<!-- ENDIF !users.email:confirmed -->" title="validated"></i>
<i class="notvalidated fa fa-times text-danger<!-- IF users.email:confirmed --> hidden<!-- ENDIF users.email:confirmed -->" title="not validated"></i>
<!-- ENDIF config.requireEmailConfirmation --> {users.email}</td>
<td class="text-right">{users.postcount}</td>
<td class="text-right">{users.reputation}</td>
<td class="text-right"><!-- IF users.flags -->{users.flags}<!-- ELSE -->0<!-- ENDIF users.flags --></td>
<td><span class="timeago" title="{users.joindateISO}"></span></td>
<td><span class="timeago" title="{users.lastonlineISO}"></span></td>
<td class="text-center"><i class="ban fa fa-gavel text-danger<!-- IF !users.banned --> hidden<!-- ENDIF !users.banned -->"></i></td>
</tr>
<!-- END users -->
</tbody>
</table>
</div>
<!-- IMPORT partials/paginator.tpl -->
</div>
</div>
</div> </div>
</div> </div>

@ -0,0 +1,13 @@
<!-- BEGIN users -->
<div data-uid="{users.uid}">
<h5>{users.username}</h5>
<div class="group-area">
<!-- BEGIN users.groups -->
<div class="group-card pull-left" data-group-name="{users.groups.nameEscaped}">
<a href="{config.relative_path}/admin/manage/groups/{users.groups.nameEncoded}"><span class="label label-default" style="color:{users.groups.textColor}; background-color: {users.groups.labelColor};"><!-- IF users.groups.icon --><i class="fa {users.groups.icon}"></i> <!-- ENDIF users.groups.icon -->{users.groups.displayName} <i class="remove-group-icon fa fa-times" role="button"></i></span></a>
</div>
<!-- END users.groups -->
</div>
<input data-uid="{users.uid}" class="form-control group-search" placeholder="[[admin/manage/users:add-group]]" />
</div>
<!-- END users -->
Loading…
Cancel
Save