feat: add pagination to groups page, api routes

use page instead of after
This commit is contained in:
Barış Soner Uşaklı
2024-11-24 11:36:02 -05:00
parent 6f083259c1
commit 49e0e1ab2d
8 changed files with 95 additions and 92 deletions

View File

@@ -103,8 +103,6 @@ get:
type: boolean type: boolean
sort: sort:
type: string type: string
nextStart:
type: number
title: title:
type: string type: string
- $ref: ../components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: ../components/schemas/Breadcrumbs.yaml#/Breadcrumbs

View File

@@ -2,15 +2,15 @@ get:
tags: tags:
- groups - groups
summary: list groups summary: list groups
description: This operation returns a list of user groups. The number of groups returned is hardcoded to 10. description: This operation returns a list of user groups. The number of groups returned is hardcoded to 15 per page.
parameters: parameters:
- in: query - in: query
name: 'after' name: 'page'
schema: schema:
type: number type: number
required: false required: false
description: An offset used to display a different subset of groups. description: Used for pagination
example: '0' example: '1'
- in: query - in: query
name: 'sort' name: 'sort'
schema: schema:

View File

@@ -1,12 +1,11 @@
'use strict'; 'use strict';
define('admin/manage/groups', [ define('admin/manage/groups', [
'categorySelector',
'slugify', 'slugify',
'api', 'api',
'bootbox', 'bootbox',
'alerts', 'alerts',
], function (categorySelector, slugify, api, bootbox, alerts) { ], function (slugify, api, bootbox, alerts) {
const Groups = {}; const Groups = {};
Groups.init = function () { Groups.init = function () {
@@ -88,30 +87,27 @@ define('admin/manage/groups', [
return ajaxify.refresh(); return ajaxify.refresh();
} }
$('.pagination').addClass('hide'); $('.pagination').addClass('hide');
const groupsEl = $('.groups-list'); api.get('/api/groups', {
socket.emit('groups.search', {
query: queryEl.val(), query: queryEl.val(),
options: { sort: 'date',
sort: 'date', hideEphemeralGroups: true,
}, }).then(renderSearchResults)
}, function (err, groups) { .catch(alerts.error);
if (err) {
return alerts.error(err);
}
app.parseAndTranslate('admin/manage/groups', 'groups', {
groups: groups,
categories: ajaxify.data.categories,
}, function (html) {
groupsEl.find('[data-groupname]').remove();
groupsEl.find('tbody').append(html);
});
});
} }
queryEl.on('keyup', utils.debounce(doSearch, 200)); queryEl.on('keyup', utils.debounce(doSearch, 200));
} }
function renderSearchResults(data) {
const groupsEl = $('.groups-list');
app.parseAndTranslate('admin/manage/groups', 'groups', {
groups: data.groups,
categories: ajaxify.data.categories,
}, function (html) {
groupsEl.find('[data-groupname]').remove();
groupsEl.find('tbody').append(html);
});
}
return Groups; return Groups;
}); });

View File

@@ -1,13 +1,11 @@
'use strict'; 'use strict';
define('forum/groups/list', [ define('forum/groups/list', [
'forum/infinitescroll', 'benchpress', 'api', 'bootbox', 'alerts', 'api', 'bootbox', 'alerts',
], function (infinitescroll, Benchpress, api, bootbox, alerts) { ], function (api, bootbox, alerts) {
const Groups = {}; const Groups = {};
Groups.init = function () { Groups.init = function () {
infinitescroll.init(Groups.loadMoreGroups);
// Group creation // Group creation
$('button[data-action="new"]').on('click', function () { $('button[data-action="new"]').on('click', function () {
bootbox.prompt('[[groups:new-group.group-name]]', function (name) { bootbox.prompt('[[groups:new-group.group-name]]', function (name) {
@@ -24,67 +22,40 @@ define('forum/groups/list', [
$('#search-sort').val(params.sort || 'alpha'); $('#search-sort').val(params.sort || 'alpha');
// Group searching // Group searching
$('#search-text').on('keyup', Groups.search); $('#search-text').on('keyup', utils.debounce(Groups.search, 200));
$('#search-button').on('click', Groups.search); $('#search-button').on('click', Groups.search);
$('#search-sort').on('change', function () { $('#search-sort').on('change', function () {
ajaxify.go('groups?sort=' + $('#search-sort').val()); ajaxify.go('groups?sort=' + $('#search-sort').val());
}); });
}; };
Groups.loadMoreGroups = function (direction) {
if (direction < 0) {
return;
}
infinitescroll.loadMore('/groups', {
sort: $('#search-sort').val(),
after: $('[component="groups/container"]').attr('data-nextstart'),
}, function (data, done) {
if (data && data.groups.length) {
Benchpress.render('partials/groups/list', {
groups: data.groups,
}).then(function (html) {
$('#groups-list').append(html);
done();
});
} else {
done();
}
if (data && data.nextStart) {
$('[component="groups/container"]').attr('data-nextstart', data.nextStart);
}
});
};
Groups.search = function () { Groups.search = function () {
const groupsEl = $('#groups-list'); api.get('/api/groups', {
const queryEl = $('#search-text'); query: $('#search-text').val(),
const sortEl = $('#search-sort'); sort: $('#search-sort').val(),
filterHidden: true,
showMembers: true,
hideEphemeralGroups: true,
}).then(renderSearchResults)
.catch(alerts.error);
socket.emit('groups.search', {
query: queryEl.val(),
options: {
sort: sortEl.val(),
filterHidden: true,
showMembers: true,
hideEphemeralGroups: true,
},
}, function (err, groups) {
if (err) {
return alerts.error(err);
}
groups = groups.filter(function (group) {
return group.name !== 'registered-users' && group.name !== 'guests';
});
Benchpress.render('partials/groups/list', {
groups: groups,
}).then(function (html) {
groupsEl.empty().append(html);
});
});
return false; return false;
}; };
function renderSearchResults(data) {
app.parseAndTranslate('partials/paginator', {
pagination: data.pagination,
}).then(function (html) {
$('.pagination-container').replaceWith(html);
});
const groupsEl = $('#groups-list');
app.parseAndTranslate('partials/groups/list', {
groups: data.groups,
}).then(function (html) {
groupsEl.empty().append(html);
});
}
return Groups; return Groups;
}); });

View File

@@ -2,8 +2,8 @@
define('forum/users', [ define('forum/users', [
'benchpress', 'api', 'alerts', 'accounts/invite', 'api', 'alerts', 'accounts/invite',
], function (Benchpress, api, alerts, AccountInvite) { ], function (api, alerts, AccountInvite) {
const Users = {}; const Users = {};
let searchResultCount = 0; let searchResultCount = 0;
@@ -88,7 +88,9 @@ define('forum/users', [
} }
function renderSearchResults(data) { function renderSearchResults(data) {
Benchpress.render('partials/paginator', { pagination: data.pagination }).then(function (html) { app.parseAndTranslate('partials/paginator', {
pagination: data.pagination,
}).then(function (html) {
$('.pagination-container').replaceWith(html); $('.pagination-container').replaceWith(html);
}); });

View File

@@ -13,8 +13,9 @@ const slugify = require('../slugify');
const groupsAPI = module.exports; const groupsAPI = module.exports;
groupsAPI.list = async (caller, data) => { groupsAPI.list = async (caller, data) => {
const groupsPerPage = 10; const page = parseInt(data.page, 10) || 1;
const start = parseInt(data.after || 0, 10); const groupsPerPage = 15;
const start = Math.max(0, page - 1) * groupsPerPage;
const stop = start + groupsPerPage - 1; const stop = start + groupsPerPage - 1;
const groupData = await groups.getGroupsBySort(data.sort, start, stop); const groupData = await groups.getGroupsBySort(data.sort, start, stop);

View File

@@ -14,22 +14,49 @@ const groupsController = module.exports;
groupsController.list = async function (req, res) { groupsController.list = async function (req, res) {
const sort = req.query.sort || 'alpha'; const sort = req.query.sort || 'alpha';
const page = parseInt(req.query.page, 10) || 1;
const [groupData, allowGroupCreation] = await Promise.all([ const [allowGroupCreation, [groupData, pageCount]] = await Promise.all([
groups.getGroupsBySort(sort, 0, 14),
privileges.global.can('group:create', req.uid), privileges.global.can('group:create', req.uid),
getGroups(req, sort, page),
]); ]);
res.render('groups/list', { res.render('groups/list', {
groups: groupData, groups: groupData,
allowGroupCreation: allowGroupCreation, allowGroupCreation: allowGroupCreation,
sort: validator.escape(String(sort)), sort: validator.escape(String(sort)),
nextStart: 15, pagination: pagination.create(page, pageCount, req.query),
title: '[[pages:groups]]', title: '[[pages:groups]]',
breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[pages:groups]]' }]), breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[pages:groups]]' }]),
}); });
}; };
async function getGroups(req, sort, page) {
const resultsPerPage = req.query.query ? 100 : 15;
const start = Math.max(0, page - 1) * resultsPerPage;
const stop = start + resultsPerPage - 1;
if (req.query.query) {
const filterHidden = req.query.filterHidden === 'true' || !await user.isAdministrator(req.uid);
const groupData = await groups.search(req.query.query, {
sort,
filterHidden: filterHidden,
showMembers: req.query.showMembers === 'true',
hideEphemeralGroups: req.query.hideEphemeralGroups === 'true',
});
const pageCount = Math.ceil(groupData.length / resultsPerPage);
return [groupData.slice(start, stop + 1), pageCount];
}
const [groupData, groupCount] = await Promise.all([
groups.getGroupsBySort(sort, start, stop),
groups.getGroupCountBySort(sort),
]);
const pageCount = Math.ceil(groupCount / resultsPerPage);
return [groupData, pageCount];
}
groupsController.details = async function (req, res, next) { groupsController.details = async function (req, res, next) {
const lowercaseSlug = req.params.slug.toLowerCase(); const lowercaseSlug = req.params.slug.toLowerCase();
if (req.params.slug !== lowercaseSlug) { if (req.params.slug !== lowercaseSlug) {

View File

@@ -76,14 +76,22 @@ Groups.getGroupsFromSet = async function (set, start, stop) {
}; };
Groups.getGroupsBySort = async function (sort, start, stop) { Groups.getGroupsBySort = async function (sort, start, stop) {
return await Groups.getGroupsFromSet(sortToSet(sort), start, stop);
};
Groups.getGroupCountBySort = async function (sort) {
return await db.sortedSetCard(sortToSet(sort));
};
function sortToSet(sort) {
let set = 'groups:visible:name'; let set = 'groups:visible:name';
if (sort === 'count') { if (sort === 'count') {
set = 'groups:visible:memberCount'; set = 'groups:visible:memberCount';
} else if (sort === 'date') { } else if (sort === 'date') {
set = 'groups:visible:createtime'; set = 'groups:visible:createtime';
} }
return await Groups.getGroupsFromSet(set, start, stop); return set;
}; }
Groups.getNonPrivilegeGroups = async function (set, start, stop, flags) { Groups.getNonPrivilegeGroups = async function (set, start, stop, flags) {
if (!flags) { if (!flags) {