diff --git a/services/web/app/src/Features/ServerAdmin/AdminController.mjs b/services/web/app/src/Features/ServerAdmin/AdminController.mjs index b2545578c1..0ab66029b1 100644 --- a/services/web/app/src/Features/ServerAdmin/AdminController.mjs +++ b/services/web/app/src/Features/ServerAdmin/AdminController.mjs @@ -6,6 +6,7 @@ import TpdsUpdateSender from '../ThirdPartyDataStore/TpdsUpdateSender.mjs' import TpdsProjectFlusher from '../ThirdPartyDataStore/TpdsProjectFlusher.mjs' import EditorRealTimeController from '../Editor/EditorRealTimeController.mjs' import SystemMessageManager from '../SystemMessages/SystemMessageManager.mjs' +import Modules from '../../infrastructure/Modules.js' const AdminController = { _sendDisconnectAllUsersMessage: delay => { @@ -30,16 +31,23 @@ const AdminController = { ) } - SystemMessageManager.getMessagesFromDB(function (error, systemMessages) { - if (error) { - return next(error) + SystemMessageManager.getMessagesFromDB( + async function (error, systemMessages) { + if (error) { + return next(error) + } + const privilegesMatrixResults = await Modules.promises.hooks.fire( + 'getPrivilegesMatrix' + ) + const privilegesMatrix = privilegesMatrixResults[0] || null + res.render('admin/index', { + title: 'System Admin', + openSockets, + systemMessages, + privilegesMatrix, + }) } - res.render('admin/index', { - title: 'System Admin', - openSockets, - systemMessages, - }) - }) + ) }, disconnectAllUsers: (req, res) => { diff --git a/services/web/app/views/admin/index.pug b/services/web/app/views/admin/index.pug index 6cd0b9a410..993f8c9595 100644 --- a/services/web/app/views/admin/index.pug +++ b/services/web/app/views/admin/index.pug @@ -16,6 +16,7 @@ block content +bookmarkable-tabset-header('system-messages', 'System Messages', true) +bookmarkable-tabset-header('open-sockets', 'Open Sockets') +bookmarkable-tabset-header('open-close-editor', 'Open/Close Editor') + +bookmarkable-tabset-header('privileges-matrix', 'Privileges Matrix') if hasFeature('saas') +bookmarkable-tabset-header('tpds', 'TPDS/Dropbox Management') @@ -71,6 +72,41 @@ block content button.btn.btn-danger(type='submit') Reopen Editor p.small Will reopen the editor after closing. + .tab-pane(role='tabpanel' id='privileges-matrix') + p This matrix shows the access levels for different admin roles across various user management privileges. The matrix is automatically generated from the code-defined roles and capabilities. + if hasFeature('saas') && privilegesMatrix + .privileges-matrix-container + table.table.table-bordered.table-striped.privileges-matrix-table + thead + tr + th Webpage and privilege + th(colspan=privilegesMatrix.roles.length) Access Level Needed For Team + tr + th + each role in privilegesMatrix.roles + th= role.displayName + tbody + - let currentSection = null + each row in privilegesMatrix.privileges + - const privilege = row.privilege + - if (currentSection !== privilege.section) + - currentSection = privilege.section + tr.section-header + td(colspan=privilegesMatrix.roles.length + 1) + strong= privilege.section + tr + td.privilege-label= privilege.label + each role in privilegesMatrix.roles + - const accessLevel = row.access[role.id] + td.access-cell(class=`access-${accessLevel}`) + span.access-badge(class=`badge-${accessLevel}`) + if accessLevel === 'yes' + | Yes + else + | No + else + p The privileges matrix is not available in this environment. + if hasFeature('saas') .tab-pane(role='tabpanel' id='tpds') h3 Flush project to TPDS diff --git a/services/web/frontend/stylesheets/pages/admin/admin.scss b/services/web/frontend/stylesheets/pages/admin/admin.scss index 9e5b330d3e..91426e9173 100644 --- a/services/web/frontend/stylesheets/pages/admin/admin.scss +++ b/services/web/frontend/stylesheets/pages/admin/admin.scss @@ -100,3 +100,76 @@ .expiration-label { vertical-align: super; } + +.privileges-matrix-container { + overflow-x: auto; + margin-top: var(--spacing-04); +} + +.privileges-matrix-table { + width: 100%; + min-width: 800px; + + thead { + background-color: var(--bg-accent-01); + position: sticky; + top: 0; + z-index: 10; + + th { + text-align: center; + font-weight: 600; + padding: var(--spacing-03); + border: 1px solid var(--border-color); + } + + th:first-child { + text-align: left; + } + } + + tbody { + .section-header { + background-color: var(--bg-accent-02); + font-weight: 600; + + td { + padding: var(--spacing-03); + border: 1px solid var(--border-color); + } + } + + .privilege-label { + padding: var(--spacing-03); + border: 1px solid var(--border-color); + text-align: left; + } + + .access-cell { + text-align: center; + padding: var(--spacing-03); + border: 1px solid var(--border-color); + vertical-align: middle; + } + + .access-badge { + display: inline-block; + padding: var(--spacing-01) var(--spacing-02); + border-radius: var(--border-radius-large); + font-weight: 500; + font-size: 0.875rem; + min-width: 40px; + text-align: center; + } + + .badge-yes { + background-color: #28a745; + color: white; + } + + .badge-no { + background-color: #8b4513; + color: white; + } + } +}