Release 1.5.13
This commit is contained in:
@@ -33,6 +33,18 @@ function buildClientRows(screens, connectionsBySlug, onboardingNameBySlug, onboa
|
||||
});
|
||||
}
|
||||
|
||||
function compareScreenNames(left, right) {
|
||||
const leftName = String(left && left.name || '').trim();
|
||||
const rightName = String(right && right.name || '').trim();
|
||||
const nameCompare = leftName.localeCompare(rightName, undefined, { sensitivity: 'base', numeric: true });
|
||||
|
||||
if (nameCompare !== 0) {
|
||||
return nameCompare;
|
||||
}
|
||||
|
||||
return String(left && left.slug || '').localeCompare(String(right && right.slug || ''), undefined, { sensitivity: 'base', numeric: true });
|
||||
}
|
||||
|
||||
function createDashboardStateService(options) {
|
||||
const pool = options && options.pool;
|
||||
const common = options && options.common;
|
||||
@@ -82,11 +94,13 @@ function createDashboardStateService(options) {
|
||||
}
|
||||
});
|
||||
|
||||
const screens = enrichScreensWithConnections(data.screens || [], connectionsBySlug, onboardingNameBySlug).map(function (screen) {
|
||||
return Object.assign({}, screen, {
|
||||
player_url: `${playerPublicBaseUrl}/screen/${encodeURIComponent(screen.slug)}`
|
||||
});
|
||||
});
|
||||
const screens = enrichScreensWithConnections(data.screens || [], connectionsBySlug, onboardingNameBySlug)
|
||||
.map(function (screen) {
|
||||
return Object.assign({}, screen, {
|
||||
player_url: `${playerPublicBaseUrl}/screen/${encodeURIComponent(screen.slug)}`
|
||||
});
|
||||
})
|
||||
.sort(compareScreenNames);
|
||||
const clients = buildClientRows(screens, connectionsBySlug, onboardingNameBySlug, onboardingNameByDeviceId, playerPublicBaseUrl, formatDashboardDate);
|
||||
const playerServiceConnected = Array.from(playerSnapshotSockets.values()).some(function (socket) {
|
||||
return socket && socket.readyState === WebSocket.OPEN;
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
function parsePageNumber(value) {
|
||||
const pageNumber = Math.floor(Number(value) || 1);
|
||||
return Math.max(1, pageNumber);
|
||||
}
|
||||
|
||||
function normalizeSortDirection(value) {
|
||||
return String(value || '').trim().toLowerCase() === 'desc' ? 'desc' : 'asc';
|
||||
}
|
||||
|
||||
function getComparableSortValue(rawValue) {
|
||||
const value = String(rawValue || '').trim();
|
||||
if (!value) {
|
||||
return { type: 'empty', value: '' };
|
||||
}
|
||||
|
||||
const numericValue = Number(value.replace(/,/g, ''));
|
||||
if (!Number.isNaN(numericValue)) {
|
||||
return { type: 'number', value: numericValue };
|
||||
}
|
||||
|
||||
const dateValue = Date.parse(value);
|
||||
if (!Number.isNaN(dateValue)) {
|
||||
return { type: 'date', value: dateValue };
|
||||
}
|
||||
|
||||
return { type: 'string', value: value.toLowerCase() };
|
||||
}
|
||||
|
||||
function compareSortValues(leftValue, rightValue) {
|
||||
if (leftValue.type === 'empty' && rightValue.type === 'empty') {
|
||||
return 0;
|
||||
}
|
||||
if (leftValue.type === 'empty') {
|
||||
return 1;
|
||||
}
|
||||
if (rightValue.type === 'empty') {
|
||||
return -1;
|
||||
}
|
||||
if (leftValue.type === rightValue.type) {
|
||||
if (leftValue.value < rightValue.value) {
|
||||
return -1;
|
||||
}
|
||||
if (leftValue.value > rightValue.value) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return String(leftValue.value).localeCompare(String(rightValue.value), undefined, { numeric: true, sensitivity: 'base' });
|
||||
}
|
||||
|
||||
function sortRows(rows, accessor, sortDirection) {
|
||||
const multiplier = normalizeSortDirection(sortDirection) === 'desc' ? -1 : 1;
|
||||
return (Array.isArray(rows) ? rows.slice() : []).sort(function (leftRow, rightRow) {
|
||||
return compareSortValues(getComparableSortValue(accessor(leftRow)), getComparableSortValue(accessor(rightRow))) * multiplier;
|
||||
});
|
||||
}
|
||||
|
||||
function createSearchMatcher(searchTerm, fields) {
|
||||
const query = String(searchTerm || '').trim().toLowerCase();
|
||||
|
||||
if (!query) {
|
||||
return function () {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
const normalizedFields = Array.isArray(fields) ? fields : [];
|
||||
return function (item) {
|
||||
const haystack = normalizedFields.map(function (field) {
|
||||
if (typeof field === 'function') {
|
||||
return field(item);
|
||||
}
|
||||
return item && field ? item[field] : '';
|
||||
}).map(function (value) {
|
||||
return String(value || '').trim().toLowerCase();
|
||||
}).join(' ');
|
||||
|
||||
return haystack.indexOf(query) !== -1;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
parsePageNumber: parsePageNumber,
|
||||
normalizeSortDirection: normalizeSortDirection,
|
||||
getComparableSortValue: getComparableSortValue,
|
||||
compareSortValues: compareSortValues,
|
||||
sortRows: sortRows,
|
||||
createSearchMatcher: createSearchMatcher
|
||||
};
|
||||
+52
-11
@@ -17,26 +17,61 @@ function buildQueryString(query) {
|
||||
return queryString ? `?${queryString}` : '';
|
||||
}
|
||||
|
||||
function createPageEntry(pageNumber, currentPage, pageParam, queryState) {
|
||||
const nextQuery = Object.assign({}, queryState, { [pageParam]: pageNumber });
|
||||
|
||||
return {
|
||||
number: pageNumber,
|
||||
active: pageNumber === currentPage,
|
||||
url: buildQueryString(nextQuery)
|
||||
};
|
||||
}
|
||||
|
||||
function createEllipsisEntry() {
|
||||
return {
|
||||
ellipsis: true
|
||||
};
|
||||
}
|
||||
|
||||
function buildPaginationPages(totalPages, currentPage, pageParam, queryState, maxVisiblePages) {
|
||||
const pages = [];
|
||||
const visiblePageCount = Math.max(1, Math.min(Number(maxVisiblePages) || 7, totalPages));
|
||||
let startPage = Math.max(1, currentPage - Math.floor(visiblePageCount / 2));
|
||||
let endPage = startPage + visiblePageCount - 1;
|
||||
const firstPage = 1;
|
||||
const lastPage = totalPages;
|
||||
|
||||
if (endPage > totalPages) {
|
||||
endPage = totalPages;
|
||||
startPage = Math.max(1, endPage - visiblePageCount + 1);
|
||||
if (totalPages <= visiblePageCount) {
|
||||
for (let pageNumber = firstPage; pageNumber <= lastPage; pageNumber += 1) {
|
||||
pages.push(createPageEntry(pageNumber, currentPage, pageParam, queryState));
|
||||
}
|
||||
|
||||
return pages;
|
||||
}
|
||||
|
||||
const innerPageCount = Math.max(1, visiblePageCount - 2);
|
||||
let startPage = Math.max(2, currentPage - Math.floor(innerPageCount / 2));
|
||||
let endPage = startPage + innerPageCount - 1;
|
||||
|
||||
if (endPage > lastPage - 1) {
|
||||
endPage = lastPage - 1;
|
||||
startPage = Math.max(2, endPage - innerPageCount + 1);
|
||||
}
|
||||
|
||||
pages.push(createPageEntry(firstPage, currentPage, pageParam, queryState));
|
||||
|
||||
if (startPage > 2) {
|
||||
pages.push(createEllipsisEntry());
|
||||
}
|
||||
|
||||
for (let pageNumber = startPage; pageNumber <= endPage; pageNumber += 1) {
|
||||
const nextQuery = Object.assign({}, queryState, { [pageParam]: pageNumber });
|
||||
pages.push({
|
||||
number: pageNumber,
|
||||
active: pageNumber === currentPage,
|
||||
url: buildQueryString(nextQuery)
|
||||
});
|
||||
pages.push(createPageEntry(pageNumber, currentPage, pageParam, queryState));
|
||||
}
|
||||
|
||||
if (endPage < lastPage - 1) {
|
||||
pages.push(createEllipsisEntry());
|
||||
}
|
||||
|
||||
pages.push(createPageEntry(lastPage, currentPage, pageParam, queryState));
|
||||
|
||||
return pages;
|
||||
}
|
||||
|
||||
@@ -51,6 +86,8 @@ function buildPagination(totalItems, currentPage, pageParam, queryState, pageSiz
|
||||
|
||||
const previousQuery = Object.assign({}, queryState, { [normalizedPageParam]: safeCurrentPage - 1 });
|
||||
const nextQuery = Object.assign({}, queryState, { [normalizedPageParam]: safeCurrentPage + 1 });
|
||||
const firstQuery = Object.assign({}, queryState, { [normalizedPageParam]: 1 });
|
||||
const lastQuery = Object.assign({}, queryState, { [normalizedPageParam]: totalPages });
|
||||
|
||||
return {
|
||||
currentPage: safeCurrentPage,
|
||||
@@ -59,8 +96,12 @@ function buildPagination(totalItems, currentPage, pageParam, queryState, pageSiz
|
||||
hasMultiplePages: totalPages > 1,
|
||||
startItem: startIndex + 1,
|
||||
endItem: endIndex,
|
||||
hasFirst: safeCurrentPage > 1,
|
||||
hasPrevious: safeCurrentPage > 1,
|
||||
hasNext: safeCurrentPage < totalPages,
|
||||
hasLast: safeCurrentPage < totalPages,
|
||||
firstUrl: buildQueryString(firstQuery),
|
||||
lastUrl: buildQueryString(lastQuery),
|
||||
previousUrl: buildQueryString(previousQuery),
|
||||
nextUrl: buildQueryString(nextQuery),
|
||||
pages: pages,
|
||||
|
||||
@@ -28,7 +28,7 @@ async function fetchRoles(pool) {
|
||||
return rows || [];
|
||||
}
|
||||
|
||||
async function fetchRolesPage(pool, page, pageSize) {
|
||||
async function fetchRolesPage(pool, page, pageSize, searchTerm, sortKey, sortDirection) {
|
||||
const paged = await fetchPagedRows(pool, {
|
||||
selectSql: `SELECT r.id, r.role_key, r.name, r.description, r.created_at, r.modified_at,
|
||||
(SELECT COUNT(*) FROM user_roles ur WHERE ur.role_id = r.id) AS user_count,
|
||||
@@ -36,6 +36,18 @@ async function fetchRolesPage(pool, page, pageSize) {
|
||||
FROM roles r
|
||||
ORDER BY r.name ASC`,
|
||||
countSql: 'SELECT COUNT(*) AS count FROM roles',
|
||||
searchColumns: ['r.role_key', 'r.name', 'r.description'],
|
||||
searchTerm: searchTerm,
|
||||
sortColumns: {
|
||||
role: 'r.name',
|
||||
description: 'r.description',
|
||||
users: 'user_count',
|
||||
permissions: 'permission_count',
|
||||
created: 'r.created_at',
|
||||
modified: 'r.modified_at'
|
||||
},
|
||||
sortKey: sortKey,
|
||||
sortDirection: sortDirection,
|
||||
page: page,
|
||||
pageSize: pageSize
|
||||
});
|
||||
@@ -122,7 +134,7 @@ async function fetchUsersWithRoles(pool) {
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchUsersWithRolesPage(pool, page, pageSize) {
|
||||
async function fetchUsersWithRolesPage(pool, page, pageSize, searchTerm, sortKey, sortDirection) {
|
||||
const paged = await fetchPagedRows(pool, {
|
||||
selectSql: `SELECT u.id, u.name, u.username, u.created_at, u.modified_at,
|
||||
COALESCE(role_data.role_names, '') AS role_names,
|
||||
@@ -138,6 +150,17 @@ async function fetchUsersWithRolesPage(pool, page, pageSize) {
|
||||
) role_data ON role_data.user_id = u.id
|
||||
ORDER BY u.id ASC`,
|
||||
countSql: 'SELECT COUNT(*) AS count FROM users',
|
||||
searchColumns: ['u.name', 'u.username', 'role_data.role_names'],
|
||||
searchTerm: searchTerm,
|
||||
sortColumns: {
|
||||
user: 'u.username',
|
||||
name: 'u.name',
|
||||
roles: 'role_names',
|
||||
created: 'u.created_at',
|
||||
modified: 'u.modified_at'
|
||||
},
|
||||
sortKey: sortKey,
|
||||
sortDirection: sortDirection,
|
||||
page: page,
|
||||
pageSize: pageSize
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user