feat(users): Profile tab, dialog shell & list CRUD wiring (#36717) - #36990
Open
AP2300 wants to merge 3 commits into
Open
feat(users): Profile tab, dialog shell & list CRUD wiring (#36717)#36990AP2300 wants to merge 3 commits into
AP2300 wants to merge 3 commits into
Conversation
Ships the Users portlet Create/Edit dialog shell with the Profile tab fully wired and placeholders for the three sibling tabs (delivered by #36718, #36719, #36720). Dialog / Profile tab: - 4-tab strip with Profile as the only functional tab; Roles, Permissions, and API Tokens render "Coming soon" placeholders - Header with avatar + name + Active status chip - Account section: first/last name, email, password + confirm, Active - Additional Info section: prefix/suffix/title/company/website - Access section: disabled (values informational only), shows admin / backend / frontend / hasConsoleAccess pulled from the loaded user - Delete User section (edit mode) with required replacement-user picker and email-typed confirmation List CRUD: - DotUsersService gains getUser/createUser/updateUser using POST/PUT/GET /api/v1/users; roles field intentionally omitted on update so backend preserves role membership (see UserResource#processRoles) - DotUsersListStore gains createUser / updateUser / deleteSingleUser - Bulk delete on the list toolbar now shows the same replacement picker instead of the old p-confirmDialog - /users route now resolves to the new users-beta portlet id Shared: - DotUsersReplacementPickerComponent — server-backed autocomplete used by both delete flows; excludes the users being deleted from suggestions client-side Test coverage: 56 tests in the portlet + 46 in data-access all pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
11 tasks
…ints
Extends the Profile tab so the Access toggles and Show Getting Started
now round-trip against the backend, and polishes a couple of visual
loose ends caught during review.
Access section:
- CMS Administrator / Back-end User / Front-end User toggles hydrate
from `GET /api/v1/roles/users/{userId}` and persist through the
`roles` field on `PUT /api/v1/users`. The load response is cached
as the full role-key list so save can strip only the three
access-role keys and preserve every other membership (personal
role, project roles, etc.).
- Save button stays disabled until roles + gettingStarted have
finished loading, so an accidental click cannot ship an incomplete
role list.
- Can Login to Admin UI stays disabled but its value is now derived
live from `cmsAdmin || backend` — reactively updated via
valueChanges. Matches the legacy behavior of read-only display
driven by role membership.
Show Getting Started:
- New GET /api/v1/toolgroups/gettingstarted/_userHasLayout on load,
and PUT _addtouser / _removefromuser on save when the toggle
diverged from the initial state. Chained off the primary save via
switchMap in the store — a toolgroup failure surfaces via the
shared error manager but does not fail the user save.
Password field:
- Adds a masked `••••••••` placeholder on the password / confirm
fields in edit mode so the empty state visually communicates
"a password is set". Leave-blank-to-keep-current behavior is
unchanged.
Password field UX cleanup:
- Header subtitle in create mode ("Fill in the details below to
create this user") removed along with its i18n key; the avatar
+ name are enough context in the header.
List polish:
- Empty Roles and Last-login cells now render blank instead of the
`—` placeholder.
Test coverage: 61 portlet tests + 46 data-access tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses M. Rojas's review thread (ts 1786391221.355219) on the Profile tab and delete flows. Delete User section (Profile tab): - Drops the red-tinted border + background; the section now uses the same neutral treatment as the other Account / Access cards. The Delete button itself keeps `severity="danger"` since that's the actual destructive action. Delete confirm dialogs (both single-user + bulk): - Replacement picker now fills the field width via `styleClass="w-full"` + `inputStyleClass="w-full"` on the shared component. - Removes the disabled-Delete pattern per the design convention of keeping buttons enabled. Clicking with an invalid form now surfaces field-level errors — red outline via PrimeNG's `[invalid]` on the picker + `ng-invalid/ng-dirty` classes on the type-to-confirm input, plus inline error text below each field. - Granular error keys (`replacement.required`, `replacement.self`, `confirm.required`, `confirm.mismatch`) replace the earlier footer summary — users see exactly which field needs attention. - Picker gains a passthrough `[invalid]` input so callers can toggle the underlying p-autoComplete error state without reaching into the shared component internals. Profile save form: - Required-field error text under firstName, lastName, email, password, and confirmPassword — chained via `@if / @else if` so each field surfaces the most relevant error (required → format → cross-field mismatch). - Explicit `[invalid]` (p-password) and `[class.ng-invalid]` / `[class.ng-dirty]` (pInputText) bindings driven by helper predicates on the profile tab. `markAllAsTouched()` in save() sets touched without dirty, so PrimeNG's default `.ng-invalid.ng-dirty` styling wasn't picking up the touched-only state. Users list empty state: - New SCSS override forces the p-datatable scroll body, table, and tbody to `height: 100%` so the empty message row can actually stretch to the tbody's computed height. Previously the tr/td auto- sized to content, leaving the icon+title+description pinned to the top instead of centered. Test coverage: 61 tests + lint clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
oidacra
added a commit
that referenced
this pull request
Aug 11, 2026
Read the design project directly rather than working from the issue summary. The list row was missing two controls it specifies. - New Experiment button in the toolbar. Creation lands with its own screen (#36990+), so it renders disabled with a tooltip rather than being absent. - Primary row action leading the Actions cell: "View Results" where results exist, "Configure" otherwise. Derived from `AllowedActionsByExperimentStatus.results` (RUNNING, ENDED) rather than restating the statuses. Disabled for now: AC10 forbids routing into the legacy UVE screens until Screens 2 and 3 land, so the row matches the design without being able to navigate. - Variants centred and Actions right-aligned, per the design. Column order already matched: the design has no Modified column, and the issue asked for "the design's columns + Modified", which is what ships. Also drops the `dot-experiment-status-tag` wrapper: a component whose only job was to render one `p-tag` earned nothing over inlining the tag and deriving severity, icon and label on the row. Its severity coverage moved to the list spec, so the mapping is still asserted for all five statuses. Reuses `experiments.action.view.results`; adds keys only where the design's copy genuinely differs from an existing string.
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.
Closes #36717
Summary
GET /api/v1/users/{userId}hydrates the edit dialog,POST /api/v1/userscreates,PUT /api/v1/usersupdates (roles field intentionally omitted so backend preserves membership — seeUserResource#processRoles)/api/v1/users/filter, excludes the users being deleted). Previously deletes silently reassigned ownership to the logged-in admin./usersrouting so the beta portlet actually lands on this UI instead of bouncing to Getting Started (PORTLET_ID_RESOLVERS.users→users-beta).Notable non-obvious calls
CMS Admin,Back-end,Front-end,Can Loginmap to backend roles (not UserForm fields), and safely editing them requires knowing the user's full role list. That's a follow-up (DWR wrapper vs. small REST endpoint decision).UserFormhandles password already; no client-side hack needed.Show Getting Startedtoggle has no backend field; kept in the UI as informational, not persisted. To be revisited if the value is needed elsewhere.Test plan
additionalInfo(prefix/suffix/title/company/website); on Save, changes persist and the list reloadspnpm nx test portlets-dot-users-portlet— 56 passingpnpm nx test data-access --testPathPatterns=dot-router— 46 passingpnpm nx lint portlets-dot-users-portlet— cleanFollow-ups (each on its own branch/PR already prepared)
🤖 Generated with Claude Code