Skip to content

feat(ui-react): add admin user management pages#6086

Open
luizhf42 wants to merge 4 commits intomasterfrom
feat/ui-react/admin-user-management
Open

feat(ui-react): add admin user management pages#6086
luizhf42 wants to merge 4 commits intomasterfrom
feat/ui-react/admin-user-management

Conversation

@luizhf42
Copy link
Copy Markdown
Member

What

Admin user list and detail pages for the React UI, covering CRUD operations, search, pagination, login-as-user impersonation, and SAML password reset.

Why

Implements features 3 and 4 from the admin panel roadmap (shellhub-io/team#93): User Administration and User Password Reset. The admin sidebar already links to /admin/users but the pages didn't exist yet.

Changes

  • hooks/useAdminUsers: Paginated list query with base64-encoded username search filter, single-user detail query. Both are admin-gated and skip 401 retries.
  • hooks/useAdminUserMutations: Create, update, delete, and reset-password mutations. All invalidate relevant TanStack Query cache keys on success — reset-password invalidates both list and detail caches so the "Set Password" button disappears after enabling local auth on a SAML-only user.
  • api/errors: Added isSdkErrorWithBody type guard to replace unsafe double-casts (err as unknown as { body: string[] }) when handling 400/409 responses with field-level error arrays.
  • pages/admin/users/index: User list with debounced server-side search, row-click navigation to detail, inline edit/delete/login-as actions. Login-as opens an impersonation token URL in a new tab.
  • pages/admin/users/UserDetails: Two-column info grid (identity + account), breadcrumb nav, edit drawer, delete confirmation, and a "Set Password" button (visible only for SAML-only users). Uses type UserDetail = GetUserResponse & { admin?: boolean } to work around the admin field being absent from the OpenAPI spec for the detail endpoint.
  • pages/admin/users/CreateUserDrawer, EditUserDrawer: Form drawers with namespace limit controls (enable → disable creation or set max), password visibility toggle, confirmed/admin checkboxes. Edit drawer prevents self-demotion and un-confirming already-confirmed users.
  • pages/admin/users/ResetPasswordDialog: Two-step dialog — confirm intent, then display generated password with copy button. Differentiates 400 ("already has local password") from generic errors.
  • App.tsx: Registered /admin/users and /admin/users/:id routes inside AdminRoute > LicenseGuard.

Testing

1016 tests passing (162 new). Coverage includes hook behavior (query guards, cache invalidation, filter encoding), type guard edge cases, and component interaction flows (form submission, error states, state reset on reopen, accessibility attributes).

@luizhf42 luizhf42 requested a review from a team as a code owner March 27, 2026 18:06
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 27, 2026

Claude finished @luizhf42's task in 3m 19s —— View job


Code Review Complete

Reviewed 17 files across code quality, security, testing, TypeScript/React patterns, and architecture. 1 inline issue posted (high severity).

Additional notes

  • The ConfirmDialog convention (consumers must catch their own errors) is also violated in UserDetails.tsx:314-319 with the same delete pattern — noted in the inline comment.
  • The type UserDetail = GetUserResponse & { admin?: boolean } workaround in UserDetails.tsx:24 exists because the OpenAPI spec for GET /admin/api/users/{id} doesn't include the admin field in its response schema, even though the Go backend returns it. Consider updating the spec to include admin so the generated client type is correct and the cast can be removed.
  • The handleLoginAs catch blocks in both index.tsx:76-78 and UserDetails.tsx:90-92 silently discard token-fetch errors. While the comment says "admin can retry", the admin has no signal that a retry is needed. Consider adding transient error feedback.

If you've addressed the feedback and want a new review, tag @shellhub-io/admin and a team member can trigger it.

@luizhf42 luizhf42 self-assigned this Mar 27, 2026
@luizhf42 luizhf42 added kind/feature New feature or request area/ui product/enterprise Issue/PR related to Enterprise Edition labels Mar 27, 2026
@luizhf42
Copy link
Copy Markdown
Member Author

OpenAPI spec gap for the missing admin field tracked in #6088.

@luizhf42 luizhf42 force-pushed the feat/ui-react/admin-user-management branch 2 times, most recently from 4699c93 to 280b373 Compare March 27, 2026 18:48
@gustavosbarreto
Copy link
Copy Markdown
Member

/review

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 27, 2026

Claude finished @gustavosbarreto's task in 50s —— View job


Code Review Complete

Reviewed 17 files across code quality, security, testing, TypeScript/React patterns, and architecture. 2 inline issues posted (2 medium).

Additional notes

  • The ConfirmDialog convention (consumers must catch their own errors) is also violated in UserDetails.tsx:318-345 with the same delete pattern — deleteError is component-level state that is never reset between dialog re-opens, though this is less impactful since there is only one user on the detail page.
  • The type UserDetail = GetUserResponse & { admin?: boolean } workaround in UserDetails.tsx:24 was already tracked in fix(openapi): add missing fields to admin user endpoints #6088.
  • useDeleteUser invalidates both "getUsers" and "getUser" on success. When deleting from UserDetails, this triggers a background refetch for the just-deleted user (404) before the navigation away completes. Consider removing "getUser" from the delete hook's invalidation list — there is no reason to refresh a query for a deleted resource.

If you've addressed the feedback and want a new review, tag @shellhub-io/admin and a team member can trigger it.

@luizhf42 luizhf42 force-pushed the feat/ui-react/admin-user-management branch 2 times, most recently from 1ace78c to 8b086b6 Compare March 27, 2026 21:01
@luizhf42 luizhf42 force-pushed the feat/ui-react/admin-user-management branch from 8b086b6 to 3809311 Compare March 30, 2026 13:40
@otavio
Copy link
Copy Markdown
Member

otavio commented Mar 30, 2026

/review

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 30, 2026

Claude finished @otavio's task in 6m 3s —— View job


Code Review Complete

Reviewed 17 files across code quality, security, testing, TypeScript/React patterns, and architecture — no issues found. The code looks good as-is.

Additional notes

  • The previous review feedback (stale deleteError, silent delete/login-as errors) has been addressed in follow-up commits.
  • The type UserDetail = GetUserResponse & { admin?: boolean } workaround and status field gap remain tracked in fix(openapi): add missing fields to admin user endpoints #6088.
  • useDeleteUser still invalidates "getUser" on success (noted in the last review), which triggers a harmless 404 refetch for the deleted resource — a minor optimization opportunity but not a bug.

If you've addressed the feedback and want a new review, tag @shellhub-io/admin and a team member can trigger it.

@luizhf42 luizhf42 force-pushed the feat/ui-react/admin-user-management branch 3 times, most recently from 81c153e to b351a36 Compare March 31, 2026 19:33
@luizhf42 luizhf42 requested a review from a team as a code owner March 31, 2026 19:33
@gustavosbarreto
Copy link
Copy Markdown
Member

/review

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 31, 2026

Claude finished @gustavosbarreto's task in 19m 2s —— View job


Code Review Complete

Reviewed 24 files across code quality, security, testing, TypeScript/React patterns, and architecture — no issues found. The code looks good as-is.

Additional notes

  • The userAdminResponse OpenAPI schema (list endpoint) does not include max_namespaces, even though the Go backend serializes it via models.User. The generated TypeScript type therefore omits it. When EditUserDrawer receives a UserAdminResponse from the list page, user.max_namespaces is undefined at the type level — though it's present at runtime because the SDK passes through untyped JSON fields. Consider adding max_namespaces to userAdminResponse.yaml so the type contract matches reality and future SDK changes (e.g., strict deserialization) don't break the edit flow.
  • The useDeleteUser hook still invalidates "getUser" on success (noted in a prior review round), which triggers a harmless 404 refetch for the just-deleted resource — minor optimization opportunity.
  • The OpenAPI spec corrections (confirmedstatus, pendingnot-confirmed, added admin field) are well-aligned with the existing backend models and migration_75.

If you've addressed the feedback and want a new review, tag @shellhub-io/admin and a team member can trigger it.

@luizhf42 luizhf42 force-pushed the feat/ui-react/admin-user-management branch 3 times, most recently from a6cec8b to 47cf669 Compare April 1, 2026 17:07
luizhf42 added 4 commits April 1, 2026 14:09
Add query hooks (useAdminUsers, useAdminUser) with paginated
list support, base64-encoded search filters, and admin-only
guards. Add mutation hooks (useCreateUser, useUpdateUser,
useDeleteUser, useResetUserPassword) with TanStack Query
cache invalidation. Add isSdkErrorWithBody type guard for
typed error handling of 400/409 API responses.
Add user list page with search, pagination, inline edit/delete
actions, and login-as-user functionality. Add user detail page
with identity/account info cards, edit drawer, create drawer,
reset password dialog for SAML-only users, and delete
confirmation. Register routes under /admin/users within the
AdminRoute > LicenseGuard group.
@luizhf42 luizhf42 force-pushed the feat/ui-react/admin-user-management branch 2 times, most recently from b9a1786 to 613f966 Compare April 1, 2026 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ui kind/feature New feature or request product/enterprise Issue/PR related to Enterprise Edition status/ready-for-testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants