feat: TeamComponent inline edit of Member.Name (opt-in)#55
Merged
Conversation
Adds an opt-in inline edit affordance for Member.Name in
TeamComponent's member grid. PlutusWave (feature 20) needs this to
drop a workaround MemberNamesPanel; consumers that haven't opted in
see no UI change.
Toggle:
<TeamComponent TMember="..." EnableMemberNameEdit="true" />
When enabled and the caller has the team:manage scope, each row's
Name column gets a pencil icon -> textbox + Save / Reset / Cancel.
Empty/whitespace input clears the override (writes null). An
"override" badge renders next to names that differ from the global
User.Name.
Persistence shape A: Platform persists, optional callback observes:
[Parameter] public EventCallback<MemberNameChangedArgs>
OnMemberNameChanged { get; set; }
Stack changes:
- ITeamService.SetMemberNameAsync (passes through to a new
protected SetTeamMemberNameAsync); public method evicts member
cache and raises TeamsListChangedEvent
- ITeamManagementService.SetMemberNameAsync gated by
[RequireScope(TeamScopes.Manage)]
- ITeamRepository<...>.SetMemberNameAsync; implementation in
TeamRepository<...> trims input, treats whitespace as null
- AuditingTeamServiceDecorator coverage with action `set-member-name`
- New public record MemberNameChangedArgs in Tharga.Team
7 new tests; 255 total passing.
…sTemplate in sample TeamComponent fixes (from manual testing on the sample): - Read-only Name column now resolves the fallback chain Member.Name ?? User.Name ?? ResolveDisplayName(user) so clearing the override displays the global User.Name (was rendering empty) - Wrap name + edit button in a horizontal RadzenStack and use an inline <span> instead of block-level RadzenText so they no longer wrap to separate lines - Replace the "override" badge with an italic name + tooltip showing the original User.Name. Cleaner, less visual noise. Sample wiring for /users: - New AppUserAdminService (sample-only) backed by IUserRepositoryCollection<UserEntity>; exposes UpdateAsync / DeleteAsync. Demonstrates the consumer-owned admin service pattern the original UsersView request expected. - UsersPage now renders <UsersListView ActionsTemplate=...> + <TeamsListView> (replaces the bare <UsersView> wrapper) so it can inject edit / delete buttons. - Edit opens a Radzen dialog (Name + Email), Delete confirms then deletes; both call NavigationManager.Refresh() to reload. - Page restricted to Roles=Developer to match the original wrapper. 255 tests still passing.
UserTeamInfo is a record (value equality). Radzen DataGrid uses the row's data as its identity key, so two UserTeamInfo records with identical (TeamName, AccessLevel, State) collide as sibling RadzenDataGridRow keys, throwing "More than one sibling has the same key value" during render. Two changes: - Add `TeamKey` field to UserTeamInfo. Each team is now distinguishable even when two teams share a display name. Consumers also benefit — they can look up the team without a name-match. - Defensively GroupBy (TeamKey, MemberKey) in the lookup so any upstream data dup of the same (team, user) pair collapses to one. The same UsersListView fix applies to consumers using ActionsTemplate that select a row and inspect Teams.
…k to null - StartMemberNameEdit now seeds the textbox with the resolved default (User.Name -> ResolveDisplayName fallback) instead of empty when there's no override yet. Reviewer can see what they're overriding. - SaveMemberName auto-clears the override when the typed name equals the resolved default — avoids creating a redundant Member.Name that duplicates User.Name.
…tead The textbox had a fixed `width: 220px` which pushed the Save / Reset / Cancel buttons off-screen on narrow columns or zoomed-out windows. Switch the textbox to `flex: 1 1 0; min-width: 0;` so it absorbs available space and shrinks freely. Buttons get `flex: 0 0 auto;` to hold their natural size. Stack gets `flex-wrap: nowrap;` so the row never breaks across lines either.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an opt-in inline edit affordance for
Member.Namein<TeamComponent>'s member grid. Lets PlutusWave (feature 20) drop a workaroundMemberNamesPanel. Off by default — existing consumers see no UI change.Toggle
When enabled and the caller has the
team:managescope, each row's Name column gets a pencil icon → textbox + Save / Reset / Cancel.UX details
User.Name ?? ResolveDisplayName(user)) when no override is set, so the reviewer can see what they're overriding.null(no override). Avoids creating redundant overrides that just duplicateUser.Name.User.Name(replaces a noisier badge approach).Member.Name ?? User.Name ?? ResolveDisplayName(user), so clearing the override never leaves the cell empty.flex: 1 1 0; min-width: 0;(shrinks freely), buttonsflex: 0 0 auto;(hold size), stackflex-wrap: nowrap;.Persistence
Shape A from the request: Platform persists, optional callback observes.
Consumer doesn't have to wire anything else for the change to land — Platform handles repository write + cache eviction +
TeamsListChangedEvent+ grid reload itself. The callback is purely observational.Stack changes
Tharga.TeamITeamService.SetMemberNameAsync;ITeamManagementService.SetMemberNameAsyncgated by[RequireScope(TeamScopes.Manage)];TeamServiceBaseevicts member cache + raisesTeamsListChangedEvent; new public recordMemberNameChangedArgs(TeamKey, MemberKey, OldName, NewName)Tharga.Team.MongoDBITeamRepository.SetMemberNameAsync+TeamRepository<...>impl (trims, whitespace → null);TeamServiceRepositoryBaseoverrideTharga.Team.ServiceAuditingTeamServiceDecoratorcovers it (actionset-member-name)Tharga.Team.BlazorEnableMemberNameEdit+OnMemberNameChangedparameters, conditional Name-column template with edit affordancesBonus fixes (caught during sample testing)
UsersListViewduplicate-key crash: addedTeamKeytoUserTeamInfo(also a useful API improvement) and defensiveGroupBy(TeamKey, MemberKey)in the lookup. Fixes a Radzen DataGrid sibling-key collision when the user-team set had any duplicate row./users: newAppUserAdminService(sample-only) backed byIUserRepositoryCollection<UserEntity>.UsersPageswitched from bare<UsersView>to<UsersListView ActionsTemplate=...>+<TeamsListView>, with edit (dialog) and delete (confirm) buttons calling the admin service. Demonstrates the consumer-owned admin pattern from the original UsersView request.Tests
7 new tests (3 service-level, 1 audit, 3 component-shape). 255 total passing.
Test plan
MemberNamesPaneland use<TeamComponent EnableMemberNameEdit="true" />