Skip to content

enhance field Validations with max text limits#3744

Merged
Baalmart merged 7 commits into
stagingfrom
validation-impro
Jul 6, 2026
Merged

enhance field Validations with max text limits#3744
Baalmart merged 7 commits into
stagingfrom
validation-impro

Conversation

@OchiengPaul442

@OchiengPaul442 OchiengPaul442 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Status of maturity (all need to be checked before merging):

  • I've tested this locally
  • I consider this code done

Screenshots (optional)

Summary by CodeRabbit

  • New Features

    • Added a new User Management experience with user details, role updates, search, export options, and improved admin navigation.
    • Introduced analytics-style user statistics with charts and summary insights.
    • Added a reusable pie chart component for dashboard visualizations.
  • Bug Fixes

    • Improved form input handling by enforcing length limits across sign-in, registration, profile, organization, feedback, surveys, roles, and security screens.
    • Refresh and loading controls now better reflect in-progress data updates.
    • Updated several action labels and tooltips for clearer feedback.
  • Documentation

    • Cleaned up testing documentation table formatting.

…list page, and role assignment functionality

- Implemented `getUsers` method in `userService` to fetch users with optional email filter.
- Defined `GetUsersResponse` type in `api.ts` for user data structure.
- Created `UserDetailPage` component for displaying individual user details and managing roles.
- Developed `UserManagementPage` component for listing users with search and pagination, including role update functionality.
- Added centralized validation limits in `validation-limits.ts` for consistent input length management across the application.
…ious components

- Updated button components to use 'loading' prop instead of 'disabled' for better user experience during async operations.
- Added 'isValidating' state to buttons in ClientsAdminPage, EmailConfigContent, OrganizationRequestsPage, RoleDetailContent, and SecurityPageContent for improved feedback during data fetching.
- Cleaned up code formatting for better readability in multiple files, including user management and role assignment components.
- Removed unnecessary comments and improved import statements for consistency.
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@OchiengPaul442, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 22 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a3fd00ef-9469-45b4-a87c-1e6732b32e3e

📥 Commits

Reviewing files that changed from the base of the PR and between f074f02 and 5d5eb71.

📒 Files selected for processing (6)
  • src/platform/src/app/(dashboard)/system/user-statistics/[id]/page.tsx
  • src/platform/src/app/(dashboard)/system/users/[id]/page.tsx
  • src/platform/src/app/(dashboard)/system/users/page.tsx
  • src/platform/src/shared/components/charts/components/ui/StatsPieChart.tsx
  • src/platform/src/shared/components/ui/input.tsx
  • src/platform/src/shared/components/ui/text-input.tsx
📝 Walkthrough

Walkthrough

This PR introduces a centralized validation-limits module and wires maxLength constraints and Zod schema limits across auth, profile, organization, feedback, security, survey, and chart forms. It also reworks user management: replaces the tabular user-statistics page with an analytics dashboard, adds a redirect for the legacy per-user statistics route, introduces new user list/detail pages backed by a new useUsers hook, userService.getUsers, GetUsersResponse type, and a StatsPieChart component, renames Team Members to Members, and adds sidebar entries. Additional changes add loading states/tooltips to several refresh/action buttons and minor formatting fixes.

Changes

Validation limits and form constraints

Layer / File(s) Summary
Validation limits module and schema updates
src/platform/src/shared/lib/validation-limits.ts, src/platform/src/shared/lib/validators.ts
New constants module defines input length limits; validators.ts schemas (login, register, forgotPwd, resetPwd, setPassword, profile, security, organizationRequest) updated to use these constants, plus new createRoleSchema/groupDetailsSchema and their inferred types.
Auth flow input constraints
.../register/page.tsx, .../login/page.tsx, .../forgotPwd/*, SetPasswordPromptDialog.tsx, SecurityTab.tsx, ProfileForm.tsx
maxLength applied to name/email/password fields across individual and organization login/registration/reset flows and profile/security tabs.
Organization, role, and request form constraints
.../org_slug/.../members, .../roles, request-organization/page.tsx, GroupDetailsSettings.tsx, CreateRoleDialog.tsx, ThemeSettings.tsx, ThemeManager.tsx
maxLength applied to role, group, request-organization, and hex color inputs.
System admin form constraints
email-configs, feedback/[feedbackId], feedback/webhooks, org-requests, security, SurveyForm.tsx, FeedbackLauncher.tsx
maxLength applied to email lists, watcher/webhook fields, security fields, survey text fields, and feedback message.
Search field and chart label limits
search-field.tsx, more-insights.tsx, BulkRoleAssignmentDialog.tsx, team-members/[memberId]/page.tsx, VisualizerChartCard.tsx
Default SEARCH_TERM_MAX added to shared SearchField; applied to search inputs; chart title/subtitle/axis/reference labels capped.

User management rework

Layer / File(s) Summary
New API types, service, and hooks
api.ts, userService.ts, useAdmin.ts
Adds GetUsersResponse, userService.getUsers, useUsers hook, and extends useUpdateUserRole cache invalidation.
StatsPieChart component
StatsPieChart.tsx, charts/index.ts
New pie chart component with no-data fallback, exported from the charts module.
User statistics analytics dashboard
user-statistics/page.tsx
Replaces tabular/export page with aggregated stats and chart panels using useUserStatistics/useUsers.
Legacy detail redirect
user-statistics/[id]/page.tsx
Client UI removed; replaced with a server redirect to /system/users/[id].
New user detail page
system/users/[id]/page.tsx
New page showing user info, role assignment, current access, and role-change dialog.
New user list page
system/users/page.tsx
New page with search/pagination, CSV/PDF export, and role-update dialog.
Sidebar and Members rename
sidebar/config/index.ts, team-members/page.tsx, metadata.ts
Adds "User Management" sidebar entries; renames Team Members page/content to Members.

Loading states, tooltips, and minor fixes

Layer / File(s) Summary
Refresh loading states and tooltips
clients/*, email-configs, org-requests, roles-permissions/*, security, feedback/page.tsx, surveys/[surveyId]
Adds loading/title props to refresh and action buttons reflecting SWR loading state.
Minor formatting fixes
home/page.tsx, info-dropdown.tsx, team-members/[memberId]/page.tsx, server-side-table.tsx, SELENIUM_TESTING.md
Reformats hook calls, click handlers, and table title default; docs table reformatting.

Estimated code review effort: 4 (Complex) | ~75 minutes

Possibly related PRs

Suggested reviewers: Baalmart, Codebmk

Poem

A rabbit hopped through fields of code,
Capping lengths on every road 🐇
Users renamed, dashboards anew,
Charts now pie-shaped, insights too,
Refresh spins gently, tooltips glow —
A tidy warren, ready to go.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: adding max text-length validation limits across fields.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch validation-impro

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • JIRA integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

New azure analytics_platform changes available for preview here

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/platform/src/shared/lib/validators.ts (1)

92-109: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Align the set-password bounds with the shared password limits

setPasswordSchema still hardcodes .min(6, ...) while the other password schemas use PASSWORD_MIN (8), so this flow accepts a weaker password than the rest. The helper text in src/platform/src/shared/components/auth/SetPasswordPromptDialog.tsx is also stale: it says “Use 6 to 30 characters...”, but the field now allows up to PASSWORD_MAX (128).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/src/shared/lib/validators.ts` around lines 92 - 109, Update
setPasswordSchema in validators.ts to use the shared PASSWORD_MIN constant
instead of hardcoding 6, and keep PASSWORD_MAX as the upper bound so it matches
the other password validators. Also update the helper text in
SetPasswordPromptDialog to reflect the shared limits (PASSWORD_MIN to
PASSWORD_MAX) instead of the stale “6 to 30 characters” copy. Ensure the
password and confirmPassword validation messaging stays consistent with the
shared auth schema.
src/platform/src/app/(dashboard)/system/security/page.tsx (1)

964-973: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Refresh button loading state won't reflect actual refreshes.

blockedLoading/flaggedLoading come from useSWR's isLoading, which is only true during the initial fetch (no cached data yet). Once data has loaded, clicking "Refresh" triggers mutate()/revalidation but isLoading stays false, so the button's loading prop never activates on manual refresh — no spinner feedback for the user.

Other files touched in this PR (email-configs/page.tsx, org-requests/page.tsx) correctly destructure isValidating from the SWR result and wire that into the refresh button instead. This file should do the same for consistency and correct UX feedback.

🔄 Suggested fix
   const {
     data: blockedAsns,
     error: blockedError,
     isLoading: blockedLoading,
+    isValidating: blockedValidating,
     mutate: mutateBlocked,
   } = useSWR('system/security/blocked-asns', fetchAllBlockedAsns, {
     revalidateOnFocus: false,
     shouldRetryOnError: false,
   });

   const {
     data: flaggedTokens,
     error: flaggedError,
     isLoading: flaggedLoading,
+    isValidating: flaggedValidating,
     mutate: mutateFlagged,
   } = useSWR('system/security/flagged-tokens', fetchAllFlaggedTokens, {
     revalidateOnFocus: false,
     shouldRetryOnError: false,
   });
...
                  onClick={handleRefreshBlocked}
-                  loading={blockedLoading}
+                  loading={blockedValidating}
...
                  onClick={handleRefreshFlagged}
-                  loading={flaggedLoading}
+                  loading={flaggedValidating}

Also applies to: 1015-1024, 501-519

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/src/app/`(dashboard)/system/security/page.tsx around lines 964 -
973, The refresh buttons in the security page are wired to SWR’s isLoading
state, which only covers the initial fetch and won’t show loading during manual
revalidation. Update the relevant useSWR destructuring in the security page to
use isValidating instead of isLoading for the blocked and flagged data hooks,
and pass that value into the Refresh button loading prop used by
handleRefreshBlocked and the flagged refresh handler so the spinner reflects
actual refreshes. Keep the change consistent with the patterns already used in
email-configs/page.tsx and org-requests/page.tsx.
src/platform/src/app/(dashboard)/system/roles-permissions/[roleId]/page.tsx (1)

38-50: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Refresh should use isValidating, not isLoading.
useRoleById() and usePermissions() already return SWR state, so the Refresh button can read isValidating from each hook. isLoading is only true for the first fetch, and this component returns early during that phase, so this spinner won’t reflect revalidation after handleRefresh() runs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/src/app/`(dashboard)/system/roles-permissions/[roleId]/page.tsx
around lines 38 - 50, The Refresh button state is tied to initial loading
instead of SWR revalidation, so it won’t show while `handleRefresh()` is
running. Update the `useRoleById` and `usePermissions` usage in the roles
permissions page to read `isValidating` from each hook instead of `isLoading`,
and use those flags in the refresh/spinner logic so the UI reflects background
revalidation correctly.
src/platform/src/app/(dashboard)/system/surveys/[surveyId]/page.tsx (1)

290-330: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use isValidating for refresh feedback isLoading only tracks the first SWR fetch, so the Refresh button at src/platform/src/app/(dashboard)/system/surveys/[surveyId]/page.tsx:634-641 and the responses table refresh affordance lower in the file won’t spin on mutate() revalidations. Switch those indicators to isValidating (or a dedicated isRefreshing flag).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/src/app/`(dashboard)/system/surveys/[surveyId]/page.tsx around
lines 290 - 330, The refresh indicators for the survey page are tied to the
initial fetch state instead of revalidation state, so they won’t reflect
`mutate()` refreshes. Update the `useSWR` hooks in `page.tsx` for `survey`,
`stats`, and `responses` to use `isValidating` (or derive a separate
`isRefreshing` flag) and wire the Refresh button and responses table affordance
to those values so they spin during revalidation.
🧹 Nitpick comments (7)
src/platform/src/shared/components/BulkRoleAssignmentDialog.tsx (1)

34-259: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Consider extracting the role-combobox logic into a shared hook.

The search/highlight/keyboard-nav state machine here (roleSearch, filteredRoles, highlightedIndex, click-outside, scroll-into-view) is duplicated almost verbatim in team-members/[memberId]/page.tsx. Not a blocker for this maxLength change, but worth consolidating into a shared useRoleCombobox hook next time either file is touched.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/src/shared/components/BulkRoleAssignmentDialog.tsx` around lines
34 - 259, Extract the duplicated role combobox state and behavior from
BulkRoleAssignmentDialog into a shared useRoleCombobox hook, since the same
search, filtering, highlight, keyboard navigation, click-outside, and
scroll-into-view logic also exists in team-members/[memberId]/page.tsx. Keep the
dialog component focused on rendering by moving roleSearch, filteredRoles,
highlightedIndex, dropdown open/close handling, and selection handlers into the
new hook, then reuse it in both places.
src/platform/src/shared/lib/validators.ts (2)

111-146: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

profileSchema.country still has no max length, unlike organizationRequestSchema.country which now uses COUNTRY_MAX in this same diff. Minor inconsistency, worth aligning for completeness.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/src/shared/lib/validators.ts` around lines 111 - 146, The
profileSchema country field is missing the same max-length validation used
elsewhere, so align it with organizationRequestSchema by applying COUNTRY_MAX to
the country validator in profileSchema. Update the country field in
validators.ts to include a max constraint alongside the existing required check,
matching the pattern used by the other schema fields in this file.

27-33: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

loginSchema.email has no upper bound.

registerSchema and forgotPwdSchema both cap email length with EMAIL_MAX, but loginSchema only caps password. For consistency (and to avoid unbounded strings hitting the auth endpoint), consider adding the same EMAIL_MAX cap here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/src/shared/lib/validators.ts` around lines 27 - 33, The
loginSchema email field is missing the same EMAIL_MAX length cap used by
registerSchema and forgotPwdSchema. Update loginSchema in validators.ts so the
email validator also enforces the shared maximum length, matching the other auth
schemas and keeping the constraint consistent. Use the existing EMAIL_MAX symbol
and keep the current required/email format checks intact.
src/platform/src/modules/user-profile/components/ProfileForm.tsx (1)

28-33: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a client-side length cap to PhoneNumberInput. ProfileForm.tsx wires maxLength for the other text fields, but the phone field can’t receive one yet because PhoneNumberInputProps doesn’t expose it. If this field should mirror the rest of the form, forward PHONE_MAX through the wrapper.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/src/modules/user-profile/components/ProfileForm.tsx` around
lines 28 - 33, The phone field is missing the same client-side length cap used
by the other profile inputs because PhoneNumberInputProps does not accept a
maxLength value. Update PhoneNumberInput and its props to forward a maxLength
prop through to the underlying input, then wire PHONE_MAX from ProfileForm so
the phone field mirrors the rest of the form.
src/platform/src/modules/themes/components/ThemeManager.tsx (1)

20-20: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Same HEX_COLOR_MAX wiring as ThemeSettings.tsx.

Nice, consistent limit applied here too. Worth noting the custom-color picker markup (input + Apply button block) is now duplicated verbatim between this file and ThemeSettings.tsx — a shared HexColorInput component could de-dupe both, but that's pre-existing structure and out of scope for this validation-limits pass.

Also applies to: 217-217

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/src/modules/themes/components/ThemeManager.tsx` at line 20,
ThemeManager.tsx should use the shared HEX_COLOR_MAX limit the same way
ThemeSettings.tsx does, so keep the import from shared/lib/validation-limits and
wire that constant into the custom color validation in ThemeManager’s color
handling logic (the ThemeManager component and its custom-color picker handlers)
instead of any local hardcoded limit. Make sure the same shared limit is used
consistently wherever hex color length is validated in this file.
src/platform/src/shared/hooks/useAdmin.ts (1)

242-252: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

No cancellation when useUsers is re-fired with a changing email.

The fetcher () => userService.getUsers(email) doesn't accept/propagate an abort signal, so if this hook backs a search input (re-firing the key on every keystroke), stale in-flight requests can resolve after newer ones, causing UI flicker with outdated results.

As per path instructions, Use AbortController for cohort endpoints and any query that can be re-fired on re-render.

🔧 Sketch of abortable fetcher
 export const useUsers = (email?: string) => {
   return useSWR(
     email ? `admin/users?email=${email}` : 'admin/users',
-    () => userService.getUsers(email),
+    (_key, { signal }: { signal?: AbortSignal } = {}) =>
+      userService.getUsers(email, { signal }),
     {
       revalidateOnFocus: false,
       revalidateOnReconnect: false,
     }
   );
 };

(Requires userService.getUsers to accept and forward an AbortSignal to the underlying HTTP client.)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/src/shared/hooks/useAdmin.ts` around lines 242 - 252, useUsers
is refiring on changing email without request cancellation, so stale user list
responses can win and flicker the UI. Update useUsers to use an
AbortController-backed fetcher and pass the abort signal through to
userService.getUsers, then ensure userService.getUsers forwards that signal to
the HTTP client so earlier in-flight requests are canceled when the email key
changes.

Source: Path instructions

src/platform/src/app/(dashboard)/system/users/page.tsx (1)

42-89: 🚀 Performance & Scalability | 🔵 Trivial | 🏗️ Heavy lift

Switch user listing to server-side paging/search
useUsers() still fetches the full user list, and this page filters/paginates it in memory before handing it to ServerSideTable. Add page/search params to useUsers/userService.getUsers so the table only loads the current slice.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/src/app/`(dashboard)/system/users/page.tsx around lines 42 - 89,
The user list is still being loaded in full and then filtered/paginated in
memory in the users page, so update the data flow to use server-side
paging/search instead. Extend useUsers and userService.getUsers to accept page,
pageSize, and search, then wire those params from the users page so
filteredUsers/paginatedUsers logic is replaced by the API response slice before
passing data to ServerSideTable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/platform/src/app/`(dashboard)/system/user-statistics/[id]/page.tsx:
- Around line 1-12: The page component’s props are using the Next 15-style async
contract, but this App Router page should use synchronous params. Update
UserDetailRedirectPageProps so params is { id: string } instead of a Promise,
and adjust UserDetailRedirectPage to read id directly before calling redirect.
Keep the redirect logic intact while aligning the type signature with the
generated page types.

In `@src/platform/src/app/`(dashboard)/system/users/[id]/page.tsx:
- Around line 76-83: Remove the arbitrary fallback in the user role resolution
logic: the primary role should come only from the user’s network or group
associations, not from the global available roles list. Update the useMemo for
primaryRoleId in the page component so it returns an empty value when no
assigned role exists, and make openRoleDialog handle that empty state without
preselecting a role in the Update Role dialog.
- Around line 136-139: The openRoleDialog callback in the user detail page is
not resetting the role search state, so old search text can carry over when the
dialog is reopened. Update openRoleDialog to clear roleSearch before opening the
dialog, matching the behavior in users/page.tsx, and keep the dependency list in
sync with any state setters or values used by the callback.

In `@src/platform/src/app/`(dashboard)/system/users/page.tsx:
- Around line 112-124: The openRoleDialog callback is still defaulting
primaryRoleId to availableRoles[0]?._id, which can prefill the Update Role
dialog with an unrelated role when a user has no assigned role. Update the logic
in openRoleDialog to derive the role only from the user’s existing group/network
role data and otherwise leave it empty, and consider extracting a shared
getPrimaryRoleId(user, availableRoles) helper so the same behavior can be reused
consistently with the user detail page.

In `@src/platform/src/shared/components/charts/components/ui/StatsPieChart.tsx`:
- Around line 39-100: StatsPieChart only treats empty arrays as no data, but it
still renders when all slice values sum to zero. Update the empty-state check in
StatsPieChart so it also returns the “No data available” UI when the total of
data[].value is 0, not just when data is missing or length is 0. Use the
existing StatsPieChart render path and the Pie/ResponsiveContainer block to keep
the fix localized.

In `@src/platform/src/shared/services/userService.ts`:
- Around line 499-514: The getUsers method still fetches the entire users list
in one call, forcing both useUsers consumers to process and slice a full payload
client-side. Update getUsers in userService to accept pagination inputs and
return paging metadata, or introduce a separate aggregation endpoint for the
stats page so it doesn’t rely on the full user dump. Keep the existing
authenticatedClient.get flow but change the response shape and downstream
consumers to use page/limit/meta instead of loading everything at once.

---

Outside diff comments:
In `@src/platform/src/app/`(dashboard)/system/roles-permissions/[roleId]/page.tsx:
- Around line 38-50: The Refresh button state is tied to initial loading instead
of SWR revalidation, so it won’t show while `handleRefresh()` is running. Update
the `useRoleById` and `usePermissions` usage in the roles permissions page to
read `isValidating` from each hook instead of `isLoading`, and use those flags
in the refresh/spinner logic so the UI reflects background revalidation
correctly.

In `@src/platform/src/app/`(dashboard)/system/security/page.tsx:
- Around line 964-973: The refresh buttons in the security page are wired to
SWR’s isLoading state, which only covers the initial fetch and won’t show
loading during manual revalidation. Update the relevant useSWR destructuring in
the security page to use isValidating instead of isLoading for the blocked and
flagged data hooks, and pass that value into the Refresh button loading prop
used by handleRefreshBlocked and the flagged refresh handler so the spinner
reflects actual refreshes. Keep the change consistent with the patterns already
used in email-configs/page.tsx and org-requests/page.tsx.

In `@src/platform/src/app/`(dashboard)/system/surveys/[surveyId]/page.tsx:
- Around line 290-330: The refresh indicators for the survey page are tied to
the initial fetch state instead of revalidation state, so they won’t reflect
`mutate()` refreshes. Update the `useSWR` hooks in `page.tsx` for `survey`,
`stats`, and `responses` to use `isValidating` (or derive a separate
`isRefreshing` flag) and wire the Refresh button and responses table affordance
to those values so they spin during revalidation.

In `@src/platform/src/shared/lib/validators.ts`:
- Around line 92-109: Update setPasswordSchema in validators.ts to use the
shared PASSWORD_MIN constant instead of hardcoding 6, and keep PASSWORD_MAX as
the upper bound so it matches the other password validators. Also update the
helper text in SetPasswordPromptDialog to reflect the shared limits
(PASSWORD_MIN to PASSWORD_MAX) instead of the stale “6 to 30 characters” copy.
Ensure the password and confirmPassword validation messaging stays consistent
with the shared auth schema.

---

Nitpick comments:
In `@src/platform/src/app/`(dashboard)/system/users/page.tsx:
- Around line 42-89: The user list is still being loaded in full and then
filtered/paginated in memory in the users page, so update the data flow to use
server-side paging/search instead. Extend useUsers and userService.getUsers to
accept page, pageSize, and search, then wire those params from the users page so
filteredUsers/paginatedUsers logic is replaced by the API response slice before
passing data to ServerSideTable.

In `@src/platform/src/modules/themes/components/ThemeManager.tsx`:
- Line 20: ThemeManager.tsx should use the shared HEX_COLOR_MAX limit the same
way ThemeSettings.tsx does, so keep the import from shared/lib/validation-limits
and wire that constant into the custom color validation in ThemeManager’s color
handling logic (the ThemeManager component and its custom-color picker handlers)
instead of any local hardcoded limit. Make sure the same shared limit is used
consistently wherever hex color length is validated in this file.

In `@src/platform/src/modules/user-profile/components/ProfileForm.tsx`:
- Around line 28-33: The phone field is missing the same client-side length cap
used by the other profile inputs because PhoneNumberInputProps does not accept a
maxLength value. Update PhoneNumberInput and its props to forward a maxLength
prop through to the underlying input, then wire PHONE_MAX from ProfileForm so
the phone field mirrors the rest of the form.

In `@src/platform/src/shared/components/BulkRoleAssignmentDialog.tsx`:
- Around line 34-259: Extract the duplicated role combobox state and behavior
from BulkRoleAssignmentDialog into a shared useRoleCombobox hook, since the same
search, filtering, highlight, keyboard navigation, click-outside, and
scroll-into-view logic also exists in team-members/[memberId]/page.tsx. Keep the
dialog component focused on rendering by moving roleSearch, filteredRoles,
highlightedIndex, dropdown open/close handling, and selection handlers into the
new hook, then reuse it in both places.

In `@src/platform/src/shared/hooks/useAdmin.ts`:
- Around line 242-252: useUsers is refiring on changing email without request
cancellation, so stale user list responses can win and flicker the UI. Update
useUsers to use an AbortController-backed fetcher and pass the abort signal
through to userService.getUsers, then ensure userService.getUsers forwards that
signal to the HTTP client so earlier in-flight requests are canceled when the
email key changes.

In `@src/platform/src/shared/lib/validators.ts`:
- Around line 111-146: The profileSchema country field is missing the same
max-length validation used elsewhere, so align it with organizationRequestSchema
by applying COUNTRY_MAX to the country validator in profileSchema. Update the
country field in validators.ts to include a max constraint alongside the
existing required check, matching the pattern used by the other schema fields in
this file.
- Around line 27-33: The loginSchema email field is missing the same EMAIL_MAX
length cap used by registerSchema and forgotPwdSchema. Update loginSchema in
validators.ts so the email validator also enforces the shared maximum length,
matching the other auth schemas and keeping the constraint consistent. Use the
existing EMAIL_MAX symbol and keep the current required/email format checks
intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2e9e1b22-df88-4e53-9329-30e40be4b386

📥 Commits

Reviewing files that changed from the base of the PR and between 14f1788 and f074f02.

📒 Files selected for processing (51)
  • src/platform/docs/SELENIUM_TESTING.md
  • src/platform/src/app/(dashboard)/(individual)/user/(auth)/creation/individual/register/page.tsx
  • src/platform/src/app/(dashboard)/(individual)/user/(auth)/forgotPwd/page.tsx
  • src/platform/src/app/(dashboard)/(individual)/user/(auth)/forgotPwd/reset/page.tsx
  • src/platform/src/app/(dashboard)/(individual)/user/(auth)/login/page.tsx
  • src/platform/src/app/(dashboard)/(individual)/user/(pages)/(layout1)/home/page.tsx
  • src/platform/src/app/(dashboard)/(organization)/org/[org_slug]/(auth)/login/page.tsx
  • src/platform/src/app/(dashboard)/(organization)/org/[org_slug]/(pages)/(layout1)/members/page.tsx
  • src/platform/src/app/(dashboard)/(organization)/org/[org_slug]/(pages)/(layout1)/roles/page.tsx
  • src/platform/src/app/(dashboard)/request-organization/page.tsx
  • src/platform/src/app/(dashboard)/system/clients/[clientId]/page.tsx
  • src/platform/src/app/(dashboard)/system/clients/page.tsx
  • src/platform/src/app/(dashboard)/system/email-configs/page.tsx
  • src/platform/src/app/(dashboard)/system/feedback/[feedbackId]/page.tsx
  • src/platform/src/app/(dashboard)/system/feedback/page.tsx
  • src/platform/src/app/(dashboard)/system/feedback/webhooks/page.tsx
  • src/platform/src/app/(dashboard)/system/org-requests/page.tsx
  • src/platform/src/app/(dashboard)/system/roles-permissions/[roleId]/page.tsx
  • src/platform/src/app/(dashboard)/system/roles-permissions/components/CreateRoleDialog.tsx
  • src/platform/src/app/(dashboard)/system/roles-permissions/page.tsx
  • src/platform/src/app/(dashboard)/system/security/page.tsx
  • src/platform/src/app/(dashboard)/system/surveys/[surveyId]/page.tsx
  • src/platform/src/app/(dashboard)/system/surveys/components/SurveyForm.tsx
  • src/platform/src/app/(dashboard)/system/team-members/[memberId]/page.tsx
  • src/platform/src/app/(dashboard)/system/team-members/page.tsx
  • src/platform/src/app/(dashboard)/system/user-statistics/[id]/page.tsx
  • src/platform/src/app/(dashboard)/system/user-statistics/page.tsx
  • src/platform/src/app/(dashboard)/system/users/[id]/page.tsx
  • src/platform/src/app/(dashboard)/system/users/page.tsx
  • src/platform/src/modules/data-visualizer/components/VisualizerChartCard.tsx
  • src/platform/src/modules/feedback/components/FeedbackLauncher.tsx
  • src/platform/src/modules/location-insights/more-insights.tsx
  • src/platform/src/modules/organization/components/GroupDetailsSettings.tsx
  • src/platform/src/modules/organization/components/ThemeSettings.tsx
  • src/platform/src/modules/themes/components/ThemeManager.tsx
  • src/platform/src/modules/user-profile/components/ProfileForm.tsx
  • src/platform/src/modules/user-profile/components/SecurityTab.tsx
  • src/platform/src/shared/components/BulkRoleAssignmentDialog.tsx
  • src/platform/src/shared/components/auth/SetPasswordPromptDialog.tsx
  • src/platform/src/shared/components/charts/components/ui/StatsPieChart.tsx
  • src/platform/src/shared/components/charts/index.ts
  • src/platform/src/shared/components/header/components/info-dropdown.tsx
  • src/platform/src/shared/components/sidebar/config/index.ts
  • src/platform/src/shared/components/ui/search-field.tsx
  • src/platform/src/shared/components/ui/server-side-table.tsx
  • src/platform/src/shared/hooks/useAdmin.ts
  • src/platform/src/shared/lib/metadata.ts
  • src/platform/src/shared/lib/validation-limits.ts
  • src/platform/src/shared/lib/validators.ts
  • src/platform/src/shared/services/userService.ts
  • src/platform/src/shared/types/api.ts

Comment thread src/platform/src/app/(dashboard)/system/users/[id]/page.tsx Outdated
Comment thread src/platform/src/app/(dashboard)/system/users/[id]/page.tsx
Comment thread src/platform/src/app/(dashboard)/system/users/page.tsx Outdated
Comment thread src/platform/src/shared/components/charts/components/ui/StatsPieChart.tsx Outdated
Comment thread src/platform/src/shared/services/userService.ts
@OchiengPaul442 OchiengPaul442 changed the title enhance field Validations with max text lengths enhance field Validations with max text limits Jul 6, 2026
@OchiengPaul442
OchiengPaul442 requested a review from Baalmart July 6, 2026 09:13
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

New azure analytics_platform changes available for preview here

@Baalmart
Baalmart merged commit c8e666b into staging Jul 6, 2026
26 of 27 checks passed
@Baalmart
Baalmart deleted the validation-impro branch July 6, 2026 10:26
@Baalmart Baalmart mentioned this pull request Jul 6, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants