From 94541c4a94665b45ba3075a9e05bd4e8b48493d8 Mon Sep 17 00:00:00 2001 From: BilalG1 Date: Wed, 22 Apr 2026 17:42:39 -0700 Subject: [PATCH] fix(dashboard): Restricted row styling + Replays empty state (#1366) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Two small UI polish fixes in `apps/dashboard`: 1. **User detail page** — the **Restricted** field now visually matches its sibling fields (`User ID`, `Display name`, `Primary email`, etc.) by reusing the same input-box appearance (`rounded-xl` border, ring, shadow, `h-8`). Previously it rendered as a bare button with `rounded-md` hover styling, which looked out of place in the user details grid. 2. **Analytics → Replays page** — the empty state previously read just *"No session replays yet"* with no guidance. It now shows a short description of what session replays are, and links out to the docs (`https://docs.stack-auth.com/docs/apps/analytics`) so new users can discover more. ## Files changed - [`apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/[userId]/page-client.tsx`](https://github.com/stack-auth/stack-auth/blob/fix/ui-bugs-users-analytics/apps/dashboard/src/app/%28main%29/%28protected%29/projects/%5BprojectId%5D/users/%5BuserId%5D/page-client.tsx) — `RestrictedStatusRow` button now styled to mirror the read-only `EditableInput` look. - [`apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/analytics/replays/page-client.tsx`](https://github.com/stack-auth/stack-auth/blob/fix/ui-bugs-users-analytics/apps/dashboard/src/app/%28main%29/%28protected%29/projects/%5BprojectId%5D/analytics/replays/page-client.tsx) — empty state now includes a description and a `StyledLink` to the docs. --- ## Bug 1 — Restricted row no longer visually orphaned Before, the *Restricted* row's value (`No`) was just plain text inside the grid; every other row (User ID, Display name, Primary email, Password, 2-factor auth, Signed up at, Risk scores, Sign-up country code) was rendered inside a styled input box. After the fix, *Restricted* uses the same boxed style — the row is still clickable and still opens the existing restriction dialog. ### Before / after toggle (full page) ![user-detail toggle](https://gist.githubusercontent.com/BilalG1/eb9ca0eeec88357728127fd4d759fa17/raw/user_detail_toggle.gif) ### Cropped view of the changed region (clearer) ![user-detail crop toggle](https://gist.githubusercontent.com/BilalG1/eb9ca0eeec88357728127fd4d759fa17/raw/user_detail_crop_toggle.gif) ### Wipe transition ![user-detail wipe](https://gist.githubusercontent.com/BilalG1/eb9ca0eeec88357728127fd4d759fa17/raw/user_detail_wipe.gif) ### Fade transition ![user-detail fade](https://gist.githubusercontent.com/BilalG1/eb9ca0eeec88357728127fd4d759fa17/raw/user_detail_fade.gif) ### Pixel diff (only the Restricted cell changes) ![user-detail pixel diff](https://gist.githubusercontent.com/BilalG1/eb9ca0eeec88357728127fd4d759fa17/raw/user_detail_pixel_diff.png) --- ## Bug 2 — Replays empty state explains itself Before, an empty replays workspace showed only *"No session replays yet"*. Users had no signal that there is anything they need to do, or where to look. After the fix, the empty state explains what session replays are, hints that replays will appear once captured, and links to the relevant docs page. > Session replays let you watch how users interact with your app. Replays will appear here once your project starts capturing them. > > [Learn more in the docs](https://docs.stack-auth.com/docs/apps/analytics) ### Before / after toggle (full page) ![replays toggle](https://gist.githubusercontent.com/BilalG1/eb9ca0eeec88357728127fd4d759fa17/raw/replays_toggle.gif?v=2) ### Cropped view of the empty state ![replays crop toggle](https://gist.githubusercontent.com/BilalG1/eb9ca0eeec88357728127fd4d759fa17/raw/replays_crop_toggle.gif?v=2) ### Wipe transition ![replays wipe](https://gist.githubusercontent.com/BilalG1/eb9ca0eeec88357728127fd4d759fa17/raw/replays_wipe.gif?v=2) ### Fade transition ![replays fade](https://gist.githubusercontent.com/BilalG1/eb9ca0eeec88357728127fd4d759fa17/raw/replays_fade.gif?v=2) ### Pixel diff ![replays pixel diff](https://gist.githubusercontent.com/BilalG1/eb9ca0eeec88357728127fd4d759fa17/raw/replays_pixel_diff.png?v=2) --- ## Test plan - [x] `pnpm --filter @stackframe/dashboard run lint` passes - [x] `pnpm --filter @stackframe/dashboard run typecheck` passes - [x] Manual verification on `localhost:8101`: - [x] User detail page renders Restricted with the same input-box style as siblings - [x] Clicking Restricted still opens the existing restriction dialog - [x] Replays empty state shows description + working docs link - [x] Light mode visually verified (dark mode untouched, classes are dark-mode-aware) ## Notes for reviewers - No change to `RestrictionDialog`, `getRestrictionReasonText`, or any restriction logic — this is purely visual. - The replays empty-state copy keeps the existing `MonitorPlayIcon` and centered layout; only added the description paragraph and the `StyledLink` (which is already imported in this file). - Comparison assets (toggles / fades / wipes / pixel diffs) are hosted in [this gist](https://gist.github.com/BilalG1/eb9ca0eeec88357728127fd4d759fa17) for reference. ## Summary by CodeRabbit * **Style** * Improved analytics empty state: centered, constrained layout; clearer primary text, added muted secondary explanatory copy and an external documentation link that opens in a new tab. * Restyled restricted-user control: refreshed appearance and spacing, truncation for long values, and stronger hover/focus feedback while preserving existing behavior. --- .../analytics/replays/page-client.tsx | 14 ++++++++-- .../users/[userId]/page-client.tsx | 26 ++++++++++--------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/analytics/replays/page-client.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/analytics/replays/page-client.tsx index 6305fea06..2790241b6 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/analytics/replays/page-client.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/analytics/replays/page-client.tsx @@ -1955,11 +1955,21 @@ export default function PageClient() { ) : ( -
+
- + No session replays yet + + Session replays let you watch how users interact with your app. For info on enabling replays,{" "} + + look here + + . +
)}
diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/[userId]/page-client.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/[userId]/page-client.tsx index b48828e3b..f9705df1d 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/[userId]/page-client.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/[userId]/page-client.tsx @@ -321,18 +321,20 @@ function RestrictedStatusRow({ user }: { user: ServerUser }) { return ( <> } name="Restricted"> - +
+ +