Skip to content

Commit 2c727bb

Browse files
adityajalkhareAditya JalkharemPokornyETM
authored
Add dedicated Manage Jenkins page with fine-grained permissions and modernized UI (#1035)
* Move resource management to dedicated Manage Jenkins subpage and modernize UI Fixes #1021, fixes #964, fixes #1018 - Convert LockableResourcesRootAction from RootAction to ManagementLink under Manage Jenkins > Configuration category - Use settings-subpage layout with Jenkins-native app-bar and tabs - Remove data-tables-api dependency; use native jenkins-table sortable - Add client-side pagination with localStorage persistence - Add resource CRUD (create, edit, delete) via JSON API endpoints - Add filter/search: structured filter for resources tab (name, label, status), text search for labels and queue tabs - Add resource property management (key-value pairs) in add/edit dialogs - Simplify Global Config page to only retain the two behavior toggles (allowEmptyOrNullValues, allowEphemeralResources) with a notice linking to the new management page - Replace Bootstrap tab markup with capsule-style tab bar matching Jenkins Dashboard design - Use event delegation for all button handlers - Add ManagementLinkTest and ResourceManagementTest (28 tests) * update docs * ran spotless * fix: add write permission for issues in auto-label PR workflow * fix: change pull_request to pull_request_target for auto-label workflow * revert auto label changes * Rerun CI * Updates: 1. Add back the sidebar entry using `LockableResourcesSidebarLink.java` 2. Add the search along with advanced filters with reload on persist * feat: implement horizontal scrolling for tables and adjust pagination controls * refactor: update resources table layout for better overflow handling * refactor: align action buttons to the start in resources table * Pulling the changes from #1033, aligning them with new UI, and many more enhancements that I am lazy to type it out * feat: implement server-side pagination for queue items and enhance UI components * enable scrollable on queues table again * Minor UI fixes which will make it look and feel better and responsive * fix: ensure case-insensitive filtering uses Locale.ENGLISH for consistency * fix: improve row selection logic in pagination to enhance filtering accuracy * feat: enhance resource management tests with queue page functionality and server-side filters * fix: update reservedBy display to link to user profile in resource table * remove queued resource handling from UI and calculations for clarity * Add overview queue metrics, clickable filter navigation, and fix note form - Add queue card metrics: longest waiting build with duration, most contended resource with build count - Make overview pills clickable: legend pills filter by status, label pills filter by label, resource name links filter by name - Add clearResourceFilters() helper to reset all filters before applying a new one from overview navigation - Fix pre-existing bug: note preview never worked because evalInnerHtmlScripts was missing (scripts in AJAX response weren't executed, so Behaviour rules for preview never registered) - Fix note form save redirecting to overview tab: intercept form submit via AJAX and reload with tab hash preserved - Fix note preview/hide-preview links navigating away from page - Wire evalInnerHtmlScripts for note form so preview works in AJAX-loaded content - Normalize pill hover behavior (consistent translateY lift) - Add /jsbundles/ to .gitignore * Rerun CI * Add fine-grained permission model and fixed the dual-layout support Add CONFIGURE permission to the existing Lockable Resources permission group for resource CRUD operations. Previously create/edit/delete required Jenkins.ADMINISTER directly. Permission defaults (impliedBy): - View: Jenkins.READ (any authenticated user can see resource status) - All others: Jenkins.ADMINISTER (preserves existing behavior) Admins can now delegate individual permissions to roles without granting full admin access. Changes: - Convert LockableResourcesRootAction from ManagementLink to RootAction for direct access at /lockable-resources/ without requiring Jenkins.MANAGE - Add LockableResourcesManagementLink so the plugin remains listed in Manage Jenkins sidebar under Configuration - Render with settings-subpage layout (Manage Jenkins sidebar) when accessed via /manage/lockable-resources/, plain layout otherwise - Add CONFIGURE permission gating create/edit/delete resource endpoints (previously Jenkins.ADMINISTER) - Gate edit and delete buttons in resource table on CONFIGURE permission - Extract shared page content to _content.jelly fragment with localization property files for all supported locales - Remove redundant LockableResourcesSidebarLink - Add tests for VIEW permission access, Jenkins.READ implied access, and denial without READ * fix: enhance access control test to handle login redirects * update docs * fix: apply spotless formatting to ManagementLink and ResourceManagementTest --------- Co-authored-by: Aditya Jalkhare <Aditya.Jalkhare@cognyte.com> Co-authored-by: Martin Pokorny <89339813+mPokornyETM@users.noreply.github.com>
1 parent e764e2d commit 2c727bb

37 files changed

Lines changed: 4282 additions & 613 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
/.idea/
44
/target/
55
/work/
6+
/jsbundles/

README.md

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@ Thx very much for supporting us.
3232

3333
### Adding lockable resources
3434

35-
1. In *Manage Jenkins* > *Configure System* go to **Lockable Resources
36-
Manager**
37-
2. Select *Add Lockable Resource*
35+
1. In *Manage Jenkins* > *Lockable Resources* (under the Configuration category)
36+
2. Click *Add Resource* in the top bar
3837

3938
Each lockable resource has the following properties:
4039

@@ -47,7 +46,7 @@ Each lockable resource has the following properties:
4746
`DK_Printer_Production`, `DK_Printer_Engineering`
4847
- **Reserved by** - Optional reserved / locked cause. If non-empty,
4948
the resource will be unavailable for jobs. i.e. `All printers are currently not available due to maintenance.`
50-
This option is still possible, but we recommend to use the page `<jenkinsRootUrl>/lockable-resources/`
49+
This option is still possible, but we recommend to use the *Manage Jenkins* > *Lockable Resources* page
5150

5251
A resource is always the one thing that is locked (or free or reserved).
5352
It exists once and has an unique name (if we take the hardware example, this may be `office_printer_14`).
@@ -397,14 +396,25 @@ Fields like *reservedBy*, *reservedTimestamp* or *note* are not supported, they
397396
398397
## lockable-resources overview
399398
400-
The page `<jenkinsRootUrl>/lockable-resources/` provides an overview over all lockable-resources.
399+
The page *Manage Jenkins* > *Lockable Resources* (also accessible at `<jenkinsRootUrl>/lockable-resources/`) provides a management dashboard for all lockable resources. When accessed from Manage Jenkins, it renders with the sidebar layout; when accessed directly via the URL, it renders as a standalone page.
400+
401+
The page has four tabs: **Overview**, **Resources**, **Labels**, and **Queue**.
402+
403+
### Overview
404+
405+
Provides at-a-glance stats including a resource donut chart (locked/reserved/free), utilization percentages, top labels, and queue metrics (longest wait, most contended resource). Cards are clickable to jump to the relevant tab.
401406

402407
### Resources
403408

404-
Provides an status overview over all resources and actions to change resource status.
409+
Provides a status overview of all resources and actions to change resource status.
410+
411+
Resources can be created, edited, and deleted directly from this tab using the **Add Resource** button and per-row edit/delete actions (requires CONFIGURE permission). Bulk actions (reserve, unreserve, unlock, steal) are available via multi-select checkboxes.
405412

406413
Name | Permission | Description
407414
-----|------------|------------
415+
Add Resource | CONFIGURE | Creates a new lockable resource.
416+
Edit (Gear Icon) | CONFIGURE | Edits an existing resource (name, description, labels, properties).
417+
Delete | CONFIGURE | Deletes a resource (only if not locked, reserved, or queued).
408418
Reserve | RESERVE | Reserves an available resource for currently logged user indefinitely (until that person, or some explicit scripted action, decides to release the resource).
409419
Unreserve | RESERVE | Un-reserves a resource that may be reserved by some person already. The user can unreserve only own resource. Administrator can unreserve any resource.
410420
Unlock | UNLOCK | Unlocks a resource that may be or not be locked by some job (or reserved by some user) already.
@@ -421,7 +431,7 @@ Provides an overview over all lockable-resources labels.
421431

422432
### Queue
423433

424-
Provides an overview over currently queued requests.
434+
Provides an overview of currently queued requests with server-side pagination for performance with large queues.
425435
A request is queued by the pipeline step `lock()`. When the requested resource(s) is currently in use (not free), then any new request for this resource will be added into the queue.
426436

427437
A resource may be requested by:
@@ -433,6 +443,21 @@ A resource may be requested by:
433443

434444
> *Note:* An empty value in the column 'Requested at' means that this build has been started in an older plugin version - [1117.v157231b_03882](https://github.com/jenkinsci/lockable-resources-plugin/releases/tag/1117.v157231b_03882) and early. In this case we cannot recognize the timestamp.
435445

446+
### Permissions
447+
448+
The plugin defines its own permission group under *Manage Jenkins* > *Security* > *Authorization*:
449+
450+
Permission | Implied by | Description
451+
-----------|------------|------------
452+
View | Jenkins.READ | See the lockable resources page and resource status.
453+
Configure | Jenkins.ADMINISTER | Create, edit, and delete resources.
454+
Unlock | Jenkins.ADMINISTER | Manually unlock a resource.
455+
Reserve | Jenkins.ADMINISTER | Reserve or unreserve a resource.
456+
Steal | Jenkins.ADMINISTER | Steal a lock from another build.
457+
Queue | Jenkins.ADMINISTER | Reorder the lock wait queue.
458+
459+
All mutating permissions default to `ADMINISTER`, preserving existing behavior. Admins can delegate individual permissions to specific roles without granting full admin access.
460+
436461
----
437462

438463
## Upgrading from 1102.vde5663d777cf

pom.xml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,6 @@
8383
<groupId>io.jenkins.plugins</groupId>
8484
<artifactId>caffeine-api</artifactId>
8585
</dependency>
86-
<dependency>
87-
<groupId>io.jenkins.plugins</groupId>
88-
<artifactId>data-tables-api</artifactId>
89-
</dependency>
9086
<dependency>
9187
<groupId>org.jenkins-ci.plugins</groupId>
9288
<artifactId>mailer</artifactId>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package org.jenkins.plugins.lockableresources.actions;
2+
3+
import edu.umd.cs.findbugs.annotations.NonNull;
4+
import hudson.Extension;
5+
import hudson.model.ManagementLink;
6+
import hudson.model.RootAction;
7+
import hudson.security.Permission;
8+
import jenkins.model.Jenkins;
9+
import org.jenkins.plugins.lockableresources.Messages;
10+
import org.kohsuke.accmod.Restricted;
11+
import org.kohsuke.accmod.restrictions.NoExternalUse;
12+
13+
/**
14+
* ManagementLink that renders the Lockable Resources page inside the Manage Jenkins
15+
* settings-subpage layout (with the Manage Jenkins sidebar). This keeps the plugin
16+
* discoverable and integrated within the management UI for admins.
17+
*
18+
* <p>Non-admin users with only the VIEW permission access the page via the
19+
* {@link LockableResourcesRootAction} at {@code /lockable-resources/} instead.
20+
*/
21+
@Extension
22+
@Restricted(NoExternalUse.class)
23+
public class LockableResourcesManagementLink extends ManagementLink {
24+
25+
@Override
26+
public String getIconFileName() {
27+
return Jenkins.get().hasPermission(LockableResourcesRootAction.VIEW) ? LockableResourcesRootAction.ICON : null;
28+
}
29+
30+
@Override
31+
public String getDisplayName() {
32+
return Messages.LockableResourcesRootAction_PermissionGroup();
33+
}
34+
35+
@Override
36+
public String getUrlName() {
37+
return "lockable-resources";
38+
}
39+
40+
@Override
41+
public String getDescription() {
42+
return Messages.LockableResourcesRootAction_ManagementLink_Description();
43+
}
44+
45+
@NonNull
46+
@Override
47+
public Category getCategory() {
48+
return Category.CONFIGURATION;
49+
}
50+
51+
@NonNull
52+
@Override
53+
public Permission getRequiredPermission() {
54+
return LockableResourcesRootAction.VIEW;
55+
}
56+
57+
/**
58+
* Returns the RootAction instance so the Jelly view can delegate content rendering.
59+
* Used by {@code index.jelly}.
60+
*/
61+
@Restricted(NoExternalUse.class)
62+
public LockableResourcesRootAction getAction() {
63+
return Jenkins.get().getExtensionList(RootAction.class).get(LockableResourcesRootAction.class);
64+
}
65+
}

0 commit comments

Comments
 (0)