mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: add privileges shortcut to groups list
fix issues with escape group names
This commit is contained in:
@@ -9,7 +9,8 @@
|
|||||||
"private": "Private",
|
"private": "Private",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"download-csv": "Download CSV",
|
"privileges": "Privileges",
|
||||||
|
"download-csv": "CSV",
|
||||||
"search-placeholder": "Search",
|
"search-placeholder": "Search",
|
||||||
"create": "Create Group",
|
"create": "Create Group",
|
||||||
"description-placeholder": "A short description about your group",
|
"description-placeholder": "A short description about your group",
|
||||||
|
|||||||
@@ -26,6 +26,10 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[component="category-selector"] {
|
||||||
|
max-width: 110px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-admin-groups {
|
.page-admin-groups {
|
||||||
|
|||||||
@@ -900,6 +900,8 @@ paths:
|
|||||||
cid:
|
cid:
|
||||||
type: number
|
type: number
|
||||||
description: A category identifier
|
description: A category identifier
|
||||||
|
group:
|
||||||
|
type: string
|
||||||
- $ref: components/schemas/CommonProps.yaml#/CommonProps
|
- $ref: components/schemas/CommonProps.yaml#/CommonProps
|
||||||
/api/admin/manage/tags:
|
/api/admin/manage/tags:
|
||||||
get:
|
get:
|
||||||
@@ -1314,6 +1316,36 @@ paths:
|
|||||||
- textColor
|
- textColor
|
||||||
- createtimeISO
|
- createtimeISO
|
||||||
- cover:thumb:url
|
- cover:thumb:url
|
||||||
|
categories:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
cid:
|
||||||
|
type: number
|
||||||
|
description: A category identifier
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
icon:
|
||||||
|
type: string
|
||||||
|
selected:
|
||||||
|
type: boolean
|
||||||
|
level:
|
||||||
|
type: string
|
||||||
|
parentCid:
|
||||||
|
type: number
|
||||||
|
description: The category identifier for the category that is the immediate
|
||||||
|
ancestor of the current category
|
||||||
|
color:
|
||||||
|
type: string
|
||||||
|
bgColor:
|
||||||
|
type: string
|
||||||
|
imageClass:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- cid
|
||||||
|
- name
|
||||||
|
- icon
|
||||||
yourid:
|
yourid:
|
||||||
type: number
|
type: number
|
||||||
- $ref: components/schemas/Pagination.yaml#/Pagination
|
- $ref: components/schemas/Pagination.yaml#/Pagination
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ define('admin/manage/group', [
|
|||||||
'iconSelect',
|
'iconSelect',
|
||||||
'admin/modules/colorpicker',
|
'admin/modules/colorpicker',
|
||||||
'translator',
|
'translator',
|
||||||
], function (memberList, iconSelect, colorpicker, translator) {
|
'categorySelector',
|
||||||
|
], function (memberList, iconSelect, colorpicker, translator, categorySelector) {
|
||||||
var Groups = {};
|
var Groups = {};
|
||||||
|
|
||||||
Groups.init = function () {
|
Groups.init = function () {
|
||||||
@@ -49,7 +50,9 @@ define('admin/manage/group', [
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$('[component="category/list"] [data-cid]').on('click', navigateToCategory);
|
categorySelector.init($('[component="category-selector"]'), function (selectedCategory) {
|
||||||
|
navigateToCategory(selectedCategory.cid);
|
||||||
|
});
|
||||||
|
|
||||||
colorpicker.enable(changeGroupLabelColor, function (hsb, hex) {
|
colorpicker.enable(changeGroupLabelColor, function (hsb, hex) {
|
||||||
groupLabelPreview.css('background-color', '#' + hex);
|
groupLabelPreview.css('background-color', '#' + hex);
|
||||||
@@ -142,11 +145,9 @@ define('admin/manage/group', [
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function navigateToCategory() {
|
function navigateToCategory(cid) {
|
||||||
var cid = $(this).attr('data-cid');
|
|
||||||
|
|
||||||
if (cid) {
|
if (cid) {
|
||||||
var url = 'admin/manage/privileges/' + cid + '?group=' + ajaxify.data.group.name;
|
var url = 'admin/manage/privileges/' + cid + '?group=' + ajaxify.data.group.nameEncoded;
|
||||||
if (app.flags && app.flags._unsaved === true) {
|
if (app.flags && app.flags._unsaved === true) {
|
||||||
translator.translate('[[global:unsaved-changes]]', function (text) {
|
translator.translate('[[global:unsaved-changes]]', function (text) {
|
||||||
bootbox.confirm(text, function (navigate) {
|
bootbox.confirm(text, function (navigate) {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
define('admin/manage/groups', ['translator', 'benchpress'], function (translator, Benchpress) {
|
define('admin/manage/groups', [
|
||||||
|
'translator', 'benchpress', 'categorySelector',
|
||||||
|
], function (translator, Benchpress, categorySelector) {
|
||||||
var Groups = {};
|
var Groups = {};
|
||||||
|
|
||||||
var intervalId = 0;
|
var intervalId = 0;
|
||||||
@@ -75,6 +77,13 @@ define('admin/manage/groups', ['translator', 'benchpress'], function (translator
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.groups-list [component="category-selector"]').each(function () {
|
||||||
|
var nameEncoded = $(this).parents('[data-name-encoded]').attr('data-name-encoded');
|
||||||
|
categorySelector.init($(this), function (selectedCategory) {
|
||||||
|
ajaxify.go('admin/manage/privileges/' + selectedCategory.cid + '?group=' + nameEncoded);
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function handleSearch() {
|
function handleSearch() {
|
||||||
|
|||||||
@@ -95,9 +95,7 @@ define('admin/manage/privileges', [
|
|||||||
$('.privilege-table-container').html(html);
|
$('.privilege-table-container').html(html);
|
||||||
Privileges.exposeAssumedPrivileges();
|
Privileges.exposeAssumedPrivileges();
|
||||||
|
|
||||||
if (groupToHighlight) {
|
hightlightRowByGroupName(groupToHighlight);
|
||||||
$('[data-group-name="' + groupToHighlight + '"]').addClass('selected');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -224,15 +222,25 @@ define('admin/manage/privileges', [
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function highlightRow() {
|
function hightlightRowByGroupName(groupName) {
|
||||||
var params = utils.params();
|
if (groupName) {
|
||||||
if (params.group) {
|
var el = $('[data-group-name]').filter(function () {
|
||||||
var el = $('[data-group-name="' + params.group + '"]');
|
return $(this).attr('data-group-name') === groupName;
|
||||||
|
});
|
||||||
if (el.length) {
|
if (el.length) {
|
||||||
return el.addClass('selected');
|
el.addClass('selected');
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
addGroupToCategory(params.group);
|
function highlightRow() {
|
||||||
|
if (ajaxify.data.group) {
|
||||||
|
if (hightlightRowByGroupName(ajaxify.data.group)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addGroupToCategory(ajaxify.data.group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,15 @@ groupsController.list = async function (req, res) {
|
|||||||
const pageCount = Math.ceil(groupNames.length / groupsPerPage);
|
const pageCount = Math.ceil(groupNames.length / groupsPerPage);
|
||||||
const start = (page - 1) * groupsPerPage;
|
const start = (page - 1) * groupsPerPage;
|
||||||
const stop = start + groupsPerPage - 1;
|
const stop = start + groupsPerPage - 1;
|
||||||
|
|
||||||
groupNames = groupNames.slice(start, stop + 1);
|
groupNames = groupNames.slice(start, stop + 1);
|
||||||
|
|
||||||
|
const allCategories = await categories.buildForSelectAll();
|
||||||
const groupData = await groups.getGroupsData(groupNames);
|
const groupData = await groups.getGroupsData(groupNames);
|
||||||
res.render('admin/manage/groups', {
|
res.render('admin/manage/groups', {
|
||||||
groups: groupData,
|
groups: groupData,
|
||||||
pagination: pagination.create(page, pageCount),
|
pagination: pagination.create(page, pageCount),
|
||||||
yourid: req.uid,
|
yourid: req.uid,
|
||||||
|
categories: allCategories,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -41,11 +41,12 @@ privilegesController.get = async function (req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const group = req.query.group ? req.query.group : '';
|
||||||
res.render('admin/manage/privileges', {
|
res.render('admin/manage/privileges', {
|
||||||
privileges: privilegesData,
|
privileges: privilegesData,
|
||||||
categories: categoriesData,
|
categories: categoriesData,
|
||||||
selectedCategory: selectedCategory,
|
selectedCategory: selectedCategory,
|
||||||
cid: cid,
|
cid: cid,
|
||||||
|
group: group,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,15 +15,14 @@
|
|||||||
<th>[[admin/manage/groups:badge]]</th>
|
<th>[[admin/manage/groups:badge]]</th>
|
||||||
<th>[[admin/manage/groups:properties]]</th>
|
<th>[[admin/manage/groups:properties]]</th>
|
||||||
<th class="hidden-xs">[[admin/manage/groups:description]]</th>
|
<th class="hidden-xs">[[admin/manage/groups:description]]</th>
|
||||||
<th class="hidden-xs text-right">[[admin/manage/groups:member-count]]</th>
|
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<!-- BEGIN groups -->
|
<!-- BEGIN groups -->
|
||||||
<tr data-groupname="{groups.displayName}">
|
<tr data-groupname="{groups.displayName}" data-name-encoded="{groups.nameEncoded}">
|
||||||
<td>
|
<td>
|
||||||
<a href="{config.relative_path}/admin/manage/groups/{groups.nameEncoded}">{groups.displayName}</a>
|
<a href="{config.relative_path}/admin/manage/groups/{groups.nameEncoded}">{groups.displayName}</a> ({groups.memberCount})
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="label label-default" style="color:{groups.textColor}; background-color: {groups.labelColor};"><!-- IF groups.icon --><i class="fa {groups.icon}"></i> <!-- ENDIF groups.icon -->{groups.userTitle}</span>
|
<span class="label label-default" style="color:{groups.textColor}; background-color: {groups.labelColor};"><!-- IF groups.icon --><i class="fa {groups.icon}"></i> <!-- ENDIF groups.icon -->{groups.userTitle}</span>
|
||||||
@@ -42,19 +41,15 @@
|
|||||||
<td class="hidden-xs">
|
<td class="hidden-xs">
|
||||||
<p class="description">{groups.description}</p>
|
<p class="description">{groups.description}</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="hidden-xs text-right">
|
|
||||||
{groups.memberCount}
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" type="button"><i class="fa fa-fw fa-ellipsis-h"></i></button>
|
<a href="{config.relative_path}/api/admin/groups/{groups.nameEncoded}/csv" class="btn btn-default">[[admin/manage/groups:download-csv]]</a>
|
||||||
<ul class="dropdown-menu dropdown-menu-right">
|
|
||||||
<li><a href="{config.relative_path}/admin/manage/groups/{groups.nameEncoded}"><i class="fa fa-fw fa-edit"></i> [[admin/manage/groups:edit]]</a></li>
|
<!-- IMPORT admin/partials/groups/privileges-select-category.tpl -->
|
||||||
<li><a href="{config.relative_path}/api/admin/groups/{groups.nameEncoded}/csv"><i class="fa fa-fw fa-file-text"></i> [[admin/manage/groups:download-csv]]</a></li>
|
|
||||||
<!-- IF !groups.system -->
|
<!-- IF !groups.system -->
|
||||||
<li data-action="delete"><a href="#"><i class="fa fa-fw fa-times"></i> [[admin/manage/groups:delete]]</a></li>
|
<button class="btn btn-danger" data-action="delete"><i class="fa fa-times"></i></button>
|
||||||
<!-- ENDIF !groups.system -->
|
<!-- ENDIF !groups.system -->
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<div component="category-selector" class="btn-group">
|
||||||
|
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||||
|
<span>[[admin/manage/groups:privileges]]</span> <span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<div component="category-selector-search" class="hidden">
|
||||||
|
<input type="text" class="form-control" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
<ul component="category/list" class="dropdown-menu category-dropdown-menu dropdown-menu-right" role="menu">
|
||||||
|
<li component="category/no-matches" role="presentation" class="category hidden">
|
||||||
|
<a role="menu-item">[[search:no-matches]]</a>
|
||||||
|
</li>
|
||||||
|
{{{each categories}}}
|
||||||
|
<li role="presentation" class="category <!-- IF categories.disabledClass -->disabled<!-- ENDIF categories.disabledClass -->" data-cid="{categories.cid}" data-name="{categories.name}" data-parent-cid="{categories.parentCid}">
|
||||||
|
<a role="menu-item">{categories.level}<span component="category-markup"><!-- IF categories.icon --><span class="fa-stack" style="{function.generateCategoryBackground}"><i style="color: {categories.color};" class="fa fa-stack-1x fa-fw {categories.icon}"></i></span><!-- ENDIF categories.icon --> {categories.name}</span></a>
|
||||||
|
</li>
|
||||||
|
{{{end}}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user