Skip to content

Commit 4ffe48a

Browse files
authored
[JENKINS-75686] reduce browser memory consumption with many roles/users (#404)
2 parents 3c95bfc + 89b7967 commit 4ffe48a

File tree

5 files changed

+60
-15
lines changed

5 files changed

+60
-15
lines changed

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,20 @@ You can assign roles to users and user groups using the _Assign Roles_ screen
6666

6767
* User groups represent authorities provided by the Security Realm (e.g. Active Directory or LDAP plugin can provide groups)
6868
* There are also two built-in groups: `authenticated` (users who logged in) and `anonymous` (any user, including ones who have not logged in)
69-
* Hovering over the header row will show a tooltip with the permissions associated to the role and the pattern.
69+
* Hovering over the header or footer row will show a tooltip with the permissions associated to the role and the pattern.
7070
* Hovering over a checkbox will show a tooltip with role, user/group and pattern.
7171

72+
#### Working with many roles
73+
The UI becomes slow to load when working with many roles. A setup with 400 item roles and one user/group assigned to each role will result in
74+
a table with 160k checkboxes. This will cause a high memory consumption of the browser and loading the page will take quite long (~ 1min and more).
75+
To improve the loading tooltips and table highlighting are disabled when the total number of checkboxes exceeds 40000 (that is 200 roles with 200 users/groups).
76+
77+
To further improve UI response times use the filters for users and roles.
78+
79+
Another limitation is that when you run Jenkins via the built-in Jetty, that the max number of parameters in a form submission is 10000 and the max formsize is 200000. This can be
80+
increased by passing the parameter `--maxParamCount=N` to the Jenkins java call (See the [Winstone](https://github.com/jenkinsci/winstone) documentation) and setting the system
81+
property `-Dorg.eclipse.jetty.server.Request.maxFormContentSize=n` at jvm start.
82+
7283
![Assign roles](/docs/images/assignRoles.png)
7384

7485
### Getting roles in pipelines

src/main/resources/com/michelin/cio/hudson/plugins/rolestrategy/RoleStrategyConfig/assign-agent-roles.jelly

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
</j:if>
5252
</j:forEach>
5353
</tbody>
54-
<local:tfoot roles="${agentGrantedRoles}" sids="${agentSIDs}"/>
54+
<local:tfoot roles="${agentGrantedRoles}" sids="${agentSIDs}" showPattern="true"/>
5555
</table>
5656

5757
<template id="newAgentRowTemplate">

src/main/resources/com/michelin/cio/hudson/plugins/rolestrategy/RoleStrategyConfig/assign-project-roles.jelly

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<j:set var="tableid" value="projectRoles"/>
3030
<j:set var="projectSIDs" value="${it.strategy.getSidEntries(it.strategy.PROJECT)}"/>
3131
<j:set var="itemGrantedRoles" value="${it.strategy.getGrantedRolesEntries(it.strategy.PROJECT)}"/>
32+
<j:set var="disableJSFeatures" value="${projectSIDs.size() * itemGrantedRoles.size() gt 40000}"/>
3233
<div id="itemUserInputFilter" data-table-id="${tableid}" data-initial-size="${projectSIDs.size()}" class="user-filter">
3334
<f:entry title="${%Filter by User/Group}">
3435
<input id="itemUserInput" class="user-input-filter jenkins-input setting-input" data-table-id="${tableid}"/>
@@ -40,36 +41,47 @@
4041
</f:entry>
4142
</div>
4243

43-
<table id="${tableid}" class="center-align global-matrix-authorization-strategy-table" name="data">
44+
<j:if test="${disableJSFeatures}">
45+
<div class="warning jenkins-!-margin-bottom-2">
46+
${%Tooltips and table highlighting have been disabled for performance reasons}
47+
</div>
48+
</j:if>
49+
50+
<table id="${tableid}" class="center-align global-matrix-authorization-strategy-table" name="data" data-disable-highlighter="${disableJSFeatures}">
4451

4552
<!-- The first row will show grouping -->
4653
<local:thead roles="${itemGrantedRoles}" showPattern="true"/>
4754
<tbody>
4855
<tr name="[USER:anonymous]" class="highlight-row">
49-
<local:userRow sid="anonymous" title="${%Anonymous}" type="${it.strategy.PROJECT}" permissionType="USER" typedescription="User" noremove="true"/>
56+
<local:userRow sid="anonymous" title="${%Anonymous}" type="${it.strategy.PROJECT}" permissionType="USER" typedescription="User" noremove="true" disableTooltips="${disableJSFeatures}"/>
5057
</tr>
5158
<tr name="[GROUP:authenticated]" class="highlight-row">
52-
<local:userRow sid="authenticated" title="authenticated" type="${it.strategy.PROJECT}" permissionType="GROUP" typedescription="Group" noremove="true"/>
59+
<local:userRow sid="authenticated" title="authenticated" type="${it.strategy.PROJECT}" permissionType="GROUP" typedescription="Group" noremove="true" disableTooltips="${disableJSFeatures}"/>
5360
</tr>
5461
<j:forEach var="entry" items="${projectSIDs}">
5562
<j:if test="${entry.sid != 'authenticated' or entry.type.toString() != 'GROUP'}">
5663
<tr name="[${entry.type}:${entry.sid}]" class="permission-row highlight-row" data-descriptor-url="${descriptorPath}">
57-
<local:userRow sid="${entry.sid}" title="${entry.sid}" permissionType="${entry.type.toString()}" typedescription="${entry.type.getDescription()}" type="${it.strategy.PROJECT}"/>
64+
<local:userRow sid="${entry.sid}" title="${entry.sid}" permissionType="${entry.type.toString()}" typedescription="${entry.type.getDescription()}" type="${it.strategy.PROJECT}" disableTooltips="${disableJSFeatures}"/>
5865
</tr>
5966
</j:if>
6067
</j:forEach>
6168
</tbody>
62-
<local:tfoot roles="${itemGrantedRoles}" sids="${projectSIDs}"/>
69+
<local:tfoot roles="${itemGrantedRoles}" sids="${projectSIDs}" showPattern="true"/>
6370
</table>
6471

6572
<template id="newItemRowTemplate">
6673
<tr class="permission-row highlight-row" data-descriptor-url="${descriptorPath}">
67-
<local:userRow title="{{USER}}" type="${it.strategy.PROJECT}" typedescription="{{USERGROUP}}"/>
74+
<local:userRow title="{{USER}}" type="${it.strategy.PROJECT}" typedescription="{{USERGROUP}}" disableTooltips="${disableJSFeatures}"/>
6875
</tr>
6976
</template>
7077

7178
<l:isAdmin>
7279
<br/>
73-
<local:addButtons sids="${projectSIDs}" tableid="${tableid}" id="newItemRowTemplate" roles="${itemGrantedRoles}" highlighter="itemTableHighlighter"/>
80+
<j:if test="${disableJSFeatures}">
81+
<local:addButtons sids="${projectSIDs}" tableid="${tableid}" id="newItemRowTemplate" roles="${itemGrantedRoles}"/>
82+
</j:if>
83+
<j:if test="${!disableJSFeatures}">
84+
<local:addButtons sids="${projectSIDs}" tableid="${tableid}" id="newItemRowTemplate" roles="${itemGrantedRoles}" highlighter="itemTableHighlighter"/>
85+
</j:if>
7486
</l:isAdmin>
7587
</j:jelly>

src/main/resources/com/michelin/cio/hudson/plugins/rolestrategy/RoleStrategyConfig/assign-roles.jelly

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,17 @@
8686
${%User/group}
8787
</td>
8888
<j:forEach var="role" items="${attrs.roles}">
89+
<j:set var="permissionList" value="&lt;b&gt;Permissions&lt;/b&gt;:"/>
90+
<j:forEach var="p" items="${role.key.permissions}">
91+
<j:set var="permissionList" value="${permissionList}&lt;br/&gt;${p.group.title}/${p.name}"/>
92+
</j:forEach>
93+
<j:set var="patternTooltip" value=""/>
94+
<j:if test="${attrs.showPattern == 'true'}">
95+
<j:set var="patternTooltip" value=" &lt;br/&gt; &lt;b&gt;Pattern&lt;/b&gt;: ${h.escape(role.key.pattern.toString())}"/>
96+
</j:if>
97+
<j:set var="permissionList" value="${permissionList} ${patternTooltip}"/>
8998
<td class="pane-header">
90-
<span>${role.key.name}</span>
99+
<span data-html-tooltip="${permissionList}">${role.key.name}</span>
91100
</td>
92101
</j:forEach>
93102
<td class="stop" />
@@ -151,9 +160,16 @@
151160
<j:if test="${attrs.type == it.strategy.GLOBAL}">
152161
<j:set var="pattern" value=""/>
153162
</j:if>
154-
<td class="rsp-highlight-input" data-html-tooltip="&lt;b&gt;Role&lt;/b&gt;: ${h.escape(r.key.name)} &lt;br/&gt; &lt;b&gt;${attrs.typedescription}&lt;/b&gt;: ${h.escape(attrs.title)} &lt;br/&gt; ${pattern}">
155-
<f:checkbox name="[${r.key.name}]" checked="${r.value.contains(permissionEntry)}"/>
156-
</td>
163+
<j:if test="${attrs.disableTooltips}">
164+
<td class="rsp-highlight-input">
165+
<f:checkbox name="[${r.key.name}]" checked="${r.value.contains(permissionEntry)}"/>
166+
</td>
167+
</j:if>
168+
<j:if test="${!attrs.disableTooltips}">
169+
<td class="rsp-highlight-input" data-html-tooltip="&lt;b&gt;Role&lt;/b&gt;: ${h.escape(r.key.name)} &lt;br/&gt; &lt;b&gt;${attrs.typedescription}&lt;/b&gt;: ${h.escape(attrs.title)} &lt;br/&gt; ${pattern}">
170+
<f:checkbox name="[${r.key.name}]" checked="${r.value.contains(permissionEntry)}"/>
171+
</td>
172+
</j:if>
157173
</j:forEach>
158174
<td class="stop">
159175
<l:isAdmin>

src/main/webapp/js/tableAssign.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ addButtonAction = function (e, template, table, tableHighlighter, tableId) {
138138
copy.setAttribute("name",'['+type+':'+name+']');
139139
tbody.appendChild(copy);
140140
Behaviour.applySubtree(table, true);
141-
tableHighlighter.scan(copy);
141+
if (tableHighlighter !== null) {
142+
tableHighlighter.scan(copy);
143+
}
142144
});
143145
}
144146

@@ -283,7 +285,11 @@ document.addEventListener('DOMContentLoaded', function() {
283285

284286
newItemRowTemplate = document.getElementById('newItemRowTemplate');
285287

286-
itemTableHighlighter = new TableHighlighter('projectRoles', 0);
288+
const projectRolesTable = document.getElementById("projectRoles");
289+
if (projectRolesTable.dataset.disableHighlighter !== "true") {
290+
itemTableHighlighter = new TableHighlighter('projectRoles', 0);
291+
}
292+
287293

288294
// agent roles initialization
289295
newAgentRowTemplate = document.getElementById('newAgentRowTemplate');

0 commit comments

Comments
 (0)