Skip to content

feat(frontend): add Roles & Permissions admin UI (EVO-1061)#55

Merged
dpaes merged 4 commits into
developfrom
fix/EVO-1061
May 14, 2026
Merged

feat(frontend): add Roles & Permissions admin UI (EVO-1061)#55
dpaes merged 4 commits into
developfrom
fix/EVO-1061

Conversation

@marcelogorutuba
Copy link
Copy Markdown
Member

@marcelogorutuba marcelogorutuba commented May 11, 2026

Summary

  • Rebase onto current develop (resolves merge conflict in menuItems.ts — keeps Products, Templates, and Roles all present)
  • Surface API error messages in handleSave, handleSaveMeta, and handleDeleteConfirm instead of generic toasts

Validation

  • evo-ai-frontend-community: pnpm exec tsc -b --noEmit → OK
  • evo-ai-frontend-community: pnpm lint → 879 pre-existing errors, zero new introduced

Changed Files

  • src/pages/Admin/Roles/RoleDetail.tsx
  • src/pages/Admin/Roles/RolesList.tsx
  • src/services/roles/rolesService.ts
  • src/components/layout/config/menuItems.ts
  • src/routes/index.tsx
  • src/i18n/config.ts
  • src/i18n/locales/*/roles.json (6 locales — new)
  • src/i18n/locales/*/layout.json (6 locales)

Related PRs

Linked Issue

  • EVO-1061

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 11, 2026

Reviewer's Guide

Implements a Roles & Permissions admin UI with list and detail pages wired to a new roles service, adds navigation and i18n wiring for the new section, gates access via permissions, and removes outdated environment warnings from SMTP and storage settings.

Sequence diagram for loading and saving role permissions in RoleDetail

sequenceDiagram
  actor AdminUser
  participant AppRouter
  participant PermissionRoute
  participant RoleDetail
  participant rolesService
  participant permissionsService
  participant apiAuth

  AdminUser->>AppRouter: navigate /settings/roles/:id
  AppRouter->>PermissionRoute: render resource=roles action=read
  PermissionRoute-->>AppRouter: [authorized]
  AppRouter-->>RoleDetail: mount
  RoleDetail->>rolesService: get(id)
  rolesService->>apiAuth: get /roles/:id
  apiAuth-->>rolesService: ApiResponse<Role>
  rolesService-->>RoleDetail: Role
  RoleDetail->>permissionsService: getResourceActions()
  permissionsService->>apiAuth: get /permissions/resource_actions
  apiAuth-->>permissionsService: ResourceActionsData
  permissionsService-->>RoleDetail: ResourceActionsData
  RoleDetail-->>RoleDetail: build selected permissions Set

  AdminUser->>RoleDetail: click savePermissions
  RoleDetail->>rolesService: bulkUpdatePermissions(role.id, permissionKeys)
  rolesService->>apiAuth: put /roles/:id/bulk_update_permissions
  apiAuth-->>rolesService: ApiResponse<Role>
  rolesService-->>RoleDetail: updated Role
Loading

Sequence diagram for listing, creating, and deleting roles in RolesList

sequenceDiagram
  actor AdminUser
  participant AppRouter
  participant PermissionRoute
  participant RolesList
  participant rolesService
  participant apiAuth

  AdminUser->>AppRouter: navigate /settings/roles
  AppRouter->>PermissionRoute: render resource=roles action=read
  PermissionRoute-->>AppRouter: [authorized]
  AppRouter-->>RolesList: mount
  RolesList->>rolesService: list()
  rolesService->>apiAuth: get /roles
  apiAuth-->>rolesService: ApiResponse<Role[]>
  rolesService-->>RolesList: Role[]

  AdminUser->>RolesList: click addRole
  RolesList-->>RolesList: open create dialog
  AdminUser->>RolesList: confirm create
  RolesList->>rolesService: create(RoleFormData)
  rolesService->>apiAuth: post /roles
  apiAuth-->>rolesService: ApiResponse<Role>
  rolesService-->>RolesList: Role
  RolesList-->>AppRouter: navigate /settings/roles/:id

  AdminUser->>RolesList: click deleteRole
  RolesList-->>RolesList: open delete dialog
  AdminUser->>RolesList: confirm delete
  RolesList->>rolesService: destroy(role.id)
  rolesService->>apiAuth: delete /roles/:id
  apiAuth-->>rolesService: {}
  rolesService-->>RolesList: void
  RolesList-->>RolesList: remove role from list
Loading

File-Level Changes

Change Details Files
Add Roles list page with search, creation, and deletion flows wired to roles API and permission checks.
  • Create RolesList page that fetches roles via rolesService.list and supports client-side search and loading state
  • Implement role creation dialog calling rolesService.create and redirecting to the role detail page on success
  • Implement delete confirmation dialog that calls rolesService.destroy, updates local list state, and disables deletion for system roles
  • Integrate permission checks via useUserPermissions to gate create/update/delete UI actions
  • Use BaseHeader and EmptyState components for consistent layout, including counts and empty/list states
src/pages/Admin/Roles/RolesList.tsx
Add Role detail page with permission tree per resource and bulk permissions update integration.
  • Create RoleDetail page that loads role and resource/actions metadata in parallel via rolesService.get and permissionsService.getResourceActions
  • Build a grouped permissions UI using cards and checkboxes per resource/action, including resource-level toggle with indeterminate state
  • Track selected permission keys in a Set and compute initial state from role.permissions_by_resource
  • Implement bulkUpdatePermissions call via rolesService.bulkUpdatePermissions, with success/error toasts and save button state handling
  • Gate editing of permissions via useUserPermissions can('roles','bulk_update_permissions') while allowing read-only view
src/pages/Admin/Roles/RoleDetail.tsx
Introduce rolesService abstraction for roles CRUD and bulk permission updates.
  • Define Role and RoleFormData interfaces reflecting backend payloads, including counts and permissions_by_resource map
  • Implement list/get/create/update/destroy endpoints targeting /roles REST API paths via apiAuth
  • Implement bulkUpdatePermissions endpoint that sends permission_keys array to /roles/:id/bulk_update_permissions
  • Export a rolesService object aggregating all role-related API methods
src/services/roles/rolesService.ts
Register routes and navigation for Roles & Permissions section, gated by roles read permission.
  • Lazily load RolesList and RoleDetail components in the main router using React.lazy and Suspense spinners
  • Add /settings/roles and /settings/roles/:id routes wrapped in PrivateRoute, CustomerRoute, MainLayout, and PermissionRoute(resource='roles', action='read')
  • Extend customer settings menu to include a 'Perfis e Permissões' entry pointing to /settings/roles with ShieldCheck icon and permission gating
  • Keep access control consistent so only users with roles read permission (e.g., super_admin and account_owner) see and access the section
src/routes/index.tsx
src/components/layout/config/menuItems.ts
Wire roles i18n namespace and add copy for menu/roles in all supported locales.
  • Register roles namespace in i18n resources for all six locales (pt-BR, pt, en, es, fr, it) in i18n config
  • Add roles.json translation files per locale to support the new Roles UI strings
  • Update adminSettings.json and layout.json in relevant locales to add menu.settings.roles label and any related admin settings copy
src/i18n/config.ts
src/i18n/locales/en/roles.json
src/i18n/locales/pt-BR/roles.json
src/i18n/locales/pt/roles.json
src/i18n/locales/es/roles.json
src/i18n/locales/fr/roles.json
src/i18n/locales/it/roles.json
src/i18n/locales/en/adminSettings.json
src/i18n/locales/en/layout.json
src/i18n/locales/pt-BR/adminSettings.json
src/i18n/locales/pt-BR/layout.json
src/i18n/locales/pt/adminSettings.json
src/i18n/locales/es/adminSettings.json
src/i18n/locales/fr/adminSettings.json
src/i18n/locales/it/adminSettings.json
Remove outdated environment warning banners from SMTP and Storage settings pages.
  • Delete envWarning informational alert block from SmtpConfig while leaving rest of the form intact
  • Delete envWarning informational alert block from StorageConfig to align with updated backend behavior
src/pages/Admin/Settings/SmtpConfig.tsx
src/pages/Admin/Settings/StorageConfig.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The Suspense fallback spinner markup for the new roles routes is duplicated; consider extracting this into a small reusable loading component to keep the router config DRY and easier to tweak later.
  • The update method in rolesService is currently unused; if there is no immediate use planned, consider removing it to avoid dead code and keep the service surface minimal.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The Suspense fallback spinner markup for the new roles routes is duplicated; consider extracting this into a small reusable loading component to keep the router config DRY and easier to tweak later.
- The `update` method in `rolesService` is currently unused; if there is no immediate use planned, consider removing it to avoid dead code and keep the service surface minimal.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

marcelogorutuba and others added 4 commits May 14, 2026 16:16
- Add /settings/roles list page with search, create modal, delete confirmation
- Add /settings/roles/:id detail page with permission tree grouped by resource
- Wire to existing roles API (index/show/create/destroy/bulk_update_permissions)
- Gate routes via PermissionRoute resource=roles action=read
- Add Roles & Permissions sidebar entry (visible to super_admin and account_owner)
- Register roles i18n namespace for all 6 locales (pt-BR, pt, en, es, fr, it)
- Remove outdated envWarning banners from SmtpConfig and StorageConfig (EVO-1049/EVO-1050 pending)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add inline rename/edit UI for custom roles in RoleDetail (H2)
- Clear permissions cache after bulk_update_permissions save and
  after role deletion in RolesList (H3)
- Translate es/fr/it roles.json from English copies (H4)
- Add menu.settings.roles key to es/fr/it/pt layout.json (H5)
- Restore SMTP/Storage env warning banners and email.envWarning
  i18n keys across all 6 locales (H6)
- Add saveChanges i18n key to all 6 roles.json locales

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n roles UI (EVO-1061)

- RoleDetail: filter selected keys against known resourceActions before
  calling bulkUpdatePermissions, preventing 422 on orphan keys (M1)
- RolesList: extract API error message from response when create fails,
  showing specific validation feedback instead of a generic toast (M2)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- handleSave extracts apiErr.message from 403 before falling back to generic toast
- handleSaveMeta and handleDeleteConfirm follow the same pattern

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@dpaes dpaes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved.

Rebased cleanly onto develop (menuItems.ts conflict resolved keeping Products, Templates, and Roles). API error surfacing in handleSave, handleSaveMeta, and handleDeleteConfirm is correct — generic toasts replaced with the backend message and validation details fallback.

One medium-priority UX bug noted in RoleDetail.tsx#handleSaveMeta: clearing an existing description is a silent no-op because metaForm.description.trim() || undefined drops the key during JSON serialization, so the backend never sees the change. Non-blocking for this merge; tracked in the Linear card.

Merging with --delete-branch.

@dpaes dpaes merged commit 4e069c5 into develop May 14, 2026
1 check passed
@dpaes dpaes deleted the fix/EVO-1061 branch May 14, 2026 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants