Merge pull request #29803 from overleaf/acf-admin-privileges-matrix

Admin privileges matrix

GitOrigin-RevId: 926c8053ab00292ee6fc0f04e0e429f307081f5e
This commit is contained in:
Anna Claire Fields
2025-11-21 11:42:53 +01:00
committed by Copybot
parent f954796709
commit 9d2f5b3cde
3 changed files with 126 additions and 9 deletions

View File

@@ -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) => {

View File

@@ -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

View File

@@ -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;
}
}
}