feat(#59): Add Profile Admin badge, role-colored badges, and RoleClaimsHelper fixes - #79
Conversation
…imsHelper fixes - Profile.razor: add distinct red Admin badge in profile header when user has Admin role - Profile.razor: Admin role badge styled red in roles list; other roles styled green - Profile.razor: add _isAdmin field derived from RoleClaimsHelper.GetRoles() - RoleClaimsHelper.cs: fix CA1859 — change GetEffectiveRoleClaimTypes return type to string[] - RoleClaimsHelper.cs: fix CA1062 — add ArgumentNullException.ThrowIfNull(identity) in AddRoleClaims - NavMenu.razor: already has AuthorizeView Roles=Admin conditional rendering (no changes needed) - MainLayout.razor: auth state already cascaded via AddCascadingAuthenticationState() in Program.cs (no changes needed) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🏗️ PR Added to Squad Triage QueueThis PR has been labeled with Next steps:
|
SummarySummary
CoverageAppHost - 0%
Domain - 87.2%
ServiceDefaults - 0%
Web - 69.4%
|
There was a problem hiding this comment.
Pull request overview
Adds role-aware UI enhancements to the Profile page and addresses analyzer-driven improvements in the role-claims helper to better support Auth0 role claim mapping.
Changes:
- Show a prominent Admin badge in the Profile header when the user has the Admin role.
- Render role badges with role-based coloring (Admin in red, others in green).
- Update
RoleClaimsHelperto use an array return type for effective role claim types and add null-guarding foridentity.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/Web/Features/UserManagement/Profile.razor | Adds Admin header badge and role-colored role badges; derives _isAdmin from extracted roles. |
| src/Web/Security/RoleClaimsHelper.cs | Optimizes internal role-claim-type computation return type and adds null validation for AddRoleClaims’ identity parameter. |
| public static void AddRoleClaims(ClaimsIdentity identity, IEnumerable<string> roleClaimTypes) | ||
| { | ||
| ArgumentNullException.ThrowIfNull(identity); | ||
|
|
||
| foreach (var roleClaimType in GetEffectiveRoleClaimTypes(identity.Claims, roleClaimTypes)) |
There was a problem hiding this comment.
AddRoleClaims accepts a non-nullable roleClaimTypes parameter but doesn't validate it (while downstream logic explicitly handles null via roleClaimTypes ?? DefaultRoleClaimTypes). This makes the method contract unclear and allows a null caller to slip through until later. Either add an explicit null guard for roleClaimTypes or make the parameter nullable to reflect the intended behavior.
| _initials = GetInitials(_displayName, _emailAddress); | ||
| _roles = RoleClaimsHelper.GetRoles(_user); | ||
| _isAdmin = _roles.Contains("Admin", StringComparer.OrdinalIgnoreCase); | ||
| _claims = _user.Claims |
There was a problem hiding this comment.
The admin badge rendering is new behavior, but the existing ProfileTests only assert that the markup contains the string "Admin" somewhere. Add/adjust a bUnit assertion that specifically verifies the header admin badge is rendered only when the user has the Admin role (and absent otherwise) to prevent regressions.
| @if (role.Equals("Admin", StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| <span class="rounded-full bg-red-100 px-3 py-1 text-sm font-semibold text-red-800 dark:bg-red-900/40 dark:text-red-300">@role</span> | ||
| } | ||
| else | ||
| { | ||
| <span class="rounded-full bg-green-100 px-3 py-1 text-sm font-semibold text-green-800 dark:bg-green-900/40 dark:text-green-300">@role</span> | ||
| } |
There was a problem hiding this comment.
The role badge markup is duplicated across the if/else branches with only color classes differing. Consider computing the class string (or using a small helper) and rendering a single <span> to reduce duplication and make future style changes less error-prone.
| @if (role.Equals("Admin", StringComparison.OrdinalIgnoreCase)) | |
| { | |
| <span class="rounded-full bg-red-100 px-3 py-1 text-sm font-semibold text-red-800 dark:bg-red-900/40 dark:text-red-300">@role</span> | |
| } | |
| else | |
| { | |
| <span class="rounded-full bg-green-100 px-3 py-1 text-sm font-semibold text-green-800 dark:bg-green-900/40 dark:text-green-300">@role</span> | |
| } | |
| var roleBadgeClass = role.Equals("Admin", StringComparison.OrdinalIgnoreCase) | |
| ? "rounded-full bg-red-100 px-3 py-1 text-sm font-semibold text-red-800 dark:bg-red-900/40 dark:text-red-300" | |
| : "rounded-full bg-green-100 px-3 py-1 text-sm font-semibold text-green-800 dark:bg-green-900/40 dark:text-green-300"; | |
| <span class="@roleBadgeClass">@role</span> |
Closes #59 - Fix duplicate file headers in RoleClaimsHelperTests.cs and ProfileTests.cs - Add GetRoles_ReturnsEmpty_WhenUserHasNoClaims - Add GetRoles_ReturnsRoles_FromAuth0NamespacedClaim - Add GetRoles_ReturnsRoles_FromStandardRoleClaim - Add GetRoles_IgnoresNonRoleClaims_WhenMixedClaimsPresent - Add ExpandRoleValues_ReturnsEmpty_WhenInputIsNullOrWhitespace - Add ExpandRoleValues_ReturnsEmpty_WhenJsonIsInvalid - Add Profile_AdminRoleBadge_HasRedColorClasses (bg-red-100, text-red-800) - Add Profile_NonAdminRoleBadge_HasGreenColorClasses (bg-green-100, text-green-800) - Add Profile_AdminHeaderBadge_HasRedBackgroundClass (bg-red-600) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🧪 Gimli (Tester) — Test coverage added ( Working as Gimli (Tester) · Closes #59 Tests added
Notes
|
|
Summary
Working as Legolas (Frontend Engineer)
Closes #59
Implements Profile page improvements, NavMenu role-aware rendering verification, and
RoleClaimsHelpercode-quality fixes.Changes
src/Web/Features/UserManagement/Profile.razorAdminrole_isAdminboolean field derived fromRoleClaimsHelper.GetRoles()src/Web/Security/RoleClaimsHelper.csGetEffectiveRoleClaimTypesreturn type fromIReadOnlyList<string>tostring[]for improved performance (compiler-recommended)ArgumentNullException.ThrowIfNull(identity)guard inAddRoleClaimsto satisfy null-validation analysis ruleNo changes required
NavMenu.razor: Already conditionally shows admin links using<AuthorizeView Roles="Admin">and<AuthorizeView Roles="Author,Admin">— fully satisfies role-aware rendering requirementMainLayout.razor:AddCascadingAuthenticationState()is registered inProgram.cs;AuthorizeRouteViewinRoutes.razorcascades auth state — no layout changes neededAcceptance Criteria
AuthorizeView)dotnet build src/Web -c Release— 0 errors, RoleClaimsHelper CA warnings resolvedTest Coverage
Gimli (Test Warden) is responsible for bUnit component tests. Existing tests:
tests/Unit.Tests/Features/UserManagement/ProfileTests.cstests/Unit.Tests/Components/Layout/NavMenuTests.cstests/Unit.Tests/Security/RoleClaimsHelperTests.cstests/Unit.Tests/Components/RazorSmokeTests.cs