[Task] Roles and Tools: Angular implementation + backend wiring
@hmoreras is already working on this.
Since Aug 12, 2026.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Goal
Ship the Angular Roles and Tools portlet end-to-end — UI, portlet.xml registration as an opt-in Beta portlet, and rollback story — in a single PR.
Frontend scope
New Nx library: core-web/libs/portlets/dot-roles/
dot-roles-shell.component.tsdot-roles-page.component.tslib.routes.tsexported asdotRolesRoutes, imported atrolesincore-web/apps/dotcms-ui/src/app/app.routes.ts- SignalStore:
DotRolesStore(role tree, selected role, active tab, per-tab pagination + search, drag state, in-flight flags) - Data-access service: extend
core-web/libs/data-access/src/lib/dot-roles/dot-roles.service.tsto cover/v1/roles/*,/v1/users/filter— replacing everyRoleAjaxDWR call needed by the Users tab and the roles tree that the Angular portlet renders directly. Permission endpoints and Tool Group endpoints (/v1/permissions/*,/v1/roles/layouts,/v1/portlet/custom,/v1/toolgroups/*, DWRRoleAjax.getRolePermissions/saveRolePermission/loadRoleLayouts/saveRoleLayouts/addNewLayout/ etc.) are not consumed from the Angular portlet in this Epic — they stay behind the iframe wrappers described below - Reuse models from
libs/dotcms-models:DotRole(extend as needed) - PrimeNG only for every UI component:
p-tree(roles hierarchy with drag-and-drop),p-tabView(Users / Permissions / Tools),p-table(users grid),p-dialog(Add Role / Edit Role / confirm-destroy),p-select(Parent dropdown),p-checkbox(Can Grant flags),p-textarea(Description),p-overlay-panelorp-autoComplete(Grant to User popover) - Users table follows the project's shared table styling conventions (see
dot-usersanddot-tagsfor reference); the design is a guide, not pixel-locked - Tests: Jest + Spectator on shell / page / store / each tab, with
data-testidselectors on every interactive element
Screen structure (per new design)
Layout: two-column shell — left Roles panel, right Role detail panel. No page-level top bar beyond the shared dotCMS header (breadcrumbs Home > Settings > Roles, site selector, notifications, user avatar).
Left panel — Roles
- Header:
ROLESlabel +Newbutton (opens Add Role dialog) Filter rolessearch input (debounced client-side filter of the loaded tree)- Hierarchical
p-treelist:- Top-level roles use a folder icon with expand/collapse chevron
- Child roles use a shield icon
- Per-row badge: user count with person icon (e.g.,
👤 2) - Hover reveals inline
+action to add a child role under that parent (opens Add Role dialog withParentprefilled)
- Drag-and-drop reparenting: dragging a role node onto a different parent updates
Role.parentvia a v1 endpoint (endpoint identified during the spike; if the current REST surface does not expose a reparent operation, file it as a backend hardening[Task]linked to this issue) - Selected node highlighted; selection drives the right-hand detail area
Right panel — Role detail
-
Header row: role icon (folder for parents, shield for children) + role name + subtitle
N users · M tools granted+Edit Rolebutton top-right -
Three tabs (
p-tabView):1. Users — full Angular implementation
Grant to Userbutton top-right opens an overlay panel with:Search usersinput (debounced, hits/v1/users/filteror the equivalent identified in the spike)- Scrollable list of users (avatar + name + email); click a row to grant this role to that user
- Below:
p-tableof current members- Columns: NAME (avatar + name), EMAIL, GRANTED FROM (chip showing the role that granted access — direct assignment shows the current role's name; inherited shows the parent role's name)
- Row hover reveals
Removeaction; multi-select supports bulk remove - Empty state: dashed card with helper text
This role has no users yetand copyGrant this role to a user using the selector above.
2. Permissions — iframe interim
- Angular tab renders an
<iframe>whosesrcpoints at a new lightweight JSP wrapper (see Backend wiring below) that hosts the existing Dojo/DWR permissions UI unchanged - No Angular re-implementation of the accordion permission matrix in this Epic; a follow-up
[Task]is filed for the eventual Angular replacement so the iframe can be swapped by dropping in the new Angular component without touching the surrounding shell - Existing permission endpoints (
RoleAjax.getRolePermissions,saveRolePermission,/v1/permissions/*where already used) stay behind the iframe - Iframe height / resize behavior: fills the tab body with a
postMessageor auto-resize helper so users don't see nested scrollbars
3. Tools — iframe interim
- Angular tab renders an
<iframe>whosesrcpoints at a new lightweight JSP wrapper hosting the existing Dojo/DWR Tool Groups management UI unchanged (available / assigned layouts,New Layoutdialog withdot-material-icon-picker, save role-layouts binding) - No Angular re-implementation of Tool Groups in this Epic because the design is still being defined; a follow-up
[Task]is filed for the eventual Angular replacement so the iframe can be swapped by dropping in the new component - Existing Tool Group endpoints (
RoleAjax.loadRoleLayouts/saveRoleLayouts/addNewLayout/ etc.,/v1/roles/layouts,/v1/portlet/custom) stay behind the iframe
Add Role dialog (triggered by New in the roles panel or the inline + on a row)
- Title:
Add Role - Fields:
Role *(required, red border on validation fail)KeyParent(p-select, defaults toNone (top level); when opened from an inline+, prefilled with that parent role)Can Grant(threep-checkbox: Users, Permissions, Tools — all checked by default per the design)Description(p-textarea)
- Actions:
Cancel/Save(Save disabled until required fields valid) closable: true,closeOnEscape: true
Edit Role dialog (triggered by Edit Role in the detail header)
- Same fields as Add Role, prefilled with the selected role's values
- Additional
Delete Roledestructive action bottom-left (red outline). Click triggers a confirm-destroy dialog closable: true,closeOnEscape: true
Confirm-destroy dialog
- Confirm-remove role, per dotCMS dialog standards (
closable: true,closeOnEscape: true)
Backend wiring
dotCMS/src/main/webapp/WEB-INF/portlet.xml:
- Add a new
roles-betaportlet entry:<portlet-class>com.dotcms.spring.portlet.PortletController</portlet-class>+<portlet-url>/roles</portlet-url>+ display nameRoles and Tools (Beta) - The existing Dojo
rolesportlet entry stays untouched so it remains reachable via the "Add Portlet" picker - Not added to any default layout or
UpgradeTask— admins opt in via "Add Portlet" in Tools - Angular route wired at
rolesincore-web/apps/dotcms-ui/src/app/app.routes.tsloading@dotcms/portlets/dot-roles/portlet - Reuse the existing
PortletID.ROLESenum entry and the existingrolesi18n title key; add aroles-betai18n title key for the Beta display name - License + role gating preserved (
requiredPortlet("roles")on v1 endpoints, admin-only surfaces enforced)
Permissions iframe wrapper JSP
- Add a new minimal JSP under
dotCMS/src/main/webapp/html/portlet/ext/roleadmin/(naming to be decided in the spike, e.g.,view_role_permissions_wrapper.jsp) that includes the existingview_role_permissions_inc.jsp+view_role_permissions_js_inc.jspoutput and nothing else - The wrapper accepts the
roleIdvia query string, initializes the existing Dojo/DWR components, and communicates readiness / size to the parent Angular tab viapostMessage - Kept intentionally thin so the eventual Angular replacement (tracked as a separate
[Task]) only requires swapping the iframesrcfor a new Angular component indot-roles-page.component.ts
Tools iframe wrapper JSP
- Add a second minimal JSP under
dotCMS/src/main/webapp/html/portlet/ext/roleadmin/(e.g.,view_role_tools_wrapper.jsp) that surfaces just the Tool Groups management section of the existingview_roles_js_inc.jsp(available / assigned grids,New Layoutdialog, save role-layouts) - Same
postMessagecontract as the permissions wrapper, sameroleIdquery-string input, same thin-wrapper philosophy so the future Angular replacement is a drop-in
Untouched files
view_roles.jspremains untouched — the wrappers are new files dedicated to the iframe use case, so the current Dojo portlet at/#/c/roleskeeps working for admins who don't opt into the Beta
Reparent endpoint
- If the drag-to-reparent flow requires a new v1 endpoint (spike output will confirm), open a backend
[Task]linked to this issue and unblock it before merge
Inputs
- Spike output from the consolidated audit issue (parity matrix + API audit + UI mapping + hardening backlog + reparent endpoint decision + iframe wrapper design for Permissions and Tools)
- Portlet conventions:
core-web/libs/portlets/CLAUDE.md - Structural reference:
core-web/libs/portlets/dot-users/(same Beta pattern, same iframe-for-undesigned-surfaces approach) andcore-web/libs/portlets/dot-velocity-playground/ - New design: https://claude.ai/design/p/20548219-a454-4b14-becf-5dd4dc0b84a1?file=Roles.dc.html&via=share (internal — auth required)
Definition of Done
Every acceptance criterion in epic #36909 passes manually against the local build:
- Beta portlet appears in the "Add Portlet" picker as
Roles and Tools (Beta) - Adding the Beta portlet to a layout serves the Angular shell at
/#/c/roles - Roles panel renders the full hierarchy with folder icons for parents and shield icons for children, expand/collapse, and user-count badges
Filter rolesnarrows the visible tree client-sideNewopens the Add Role dialog; save creates the role and refreshes the tree- Inline
+on a parent row opens Add Role dialog withParentprefilled - Drag-and-drop of a role onto a different parent persists the reparent via v1 endpoint
Edit Rolein the detail header opens the Edit dialog; save updates the role;Delete Roleopens a confirm-destroy and removes the role- Users tab:
Grant to Userpopover searches users and grants the role on selection; the members table renders NAME / EMAIL / GRANTED FROM (with inheritance chip); remove and bulk-remove work; empty state matches the design copy - Permissions tab: iframe loads the new JSP wrapper and renders the existing permissions UI functional (matrix, cascade toggle, apply changes, cascade-progress) — behavior parity with the current Dojo portlet
- Tools tab: iframe loads the new JSP wrapper and renders the existing Tool Groups management UI functional (available / assigned layouts,
New Layoutdialog, save role-layouts) — behavior parity with the current Dojo portlet - License + role gating preserved on every write path
- Dojo
rolesportlet entry remains registered so admins can revert by removing the Beta portlet from their layout - Follow-up
[Task]filed for the Angular replacement of the Permissions tab, linked to this issue and to epic #36909 - Follow-up
[Task]filed for the Angular replacement of the Tools tab (once design is defined), linked to this issue and to epic #36909
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.