mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
fix(dashboard): Restricted row styling + Replays empty state (#1366)
## 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)  ### Cropped view of the changed region (clearer)  ### Wipe transition  ### Fade transition  ### Pixel diff (only the Restricted cell changes)  --- ## 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)  ### Cropped view of the empty state  ### Wipe transition  ### Fade transition  ### Pixel diff  --- ## 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. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## 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. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
0532a18c36
commit
94541c4a94
@ -1955,11 +1955,21 @@ export default function PageClient() {
|
||||
</Typography>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center p-6">
|
||||
<div className="text-center p-6 max-w-md mx-auto">
|
||||
<MonitorPlayIcon className="h-12 w-12 text-muted-foreground/40 mx-auto" />
|
||||
<Typography className="mt-3 text-sm font-medium text-muted-foreground">
|
||||
<Typography className="mt-3 text-sm font-medium">
|
||||
No session replays yet
|
||||
</Typography>
|
||||
<Typography className="mt-2 text-sm text-muted-foreground">
|
||||
Session replays let you watch how users interact with your app. For info on enabling replays,{" "}
|
||||
<StyledLink
|
||||
href="https://docs.stack-auth.com/docs/apps/analytics"
|
||||
target="_blank"
|
||||
>
|
||||
look here
|
||||
</StyledLink>
|
||||
.
|
||||
</Typography>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -321,18 +321,20 @@ function RestrictedStatusRow({ user }: { user: ServerUser }) {
|
||||
return (
|
||||
<>
|
||||
<UserInfo icon={<ProhibitIcon size={16}/>} name="Restricted">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setDialogOpen(true)}
|
||||
className={cn(
|
||||
"w-full text-left px-1 py-0 rounded-md text-sm",
|
||||
"hover:ring-1 hover:ring-slate-300 dark:hover:ring-gray-500 hover:bg-slate-50 dark:hover:bg-gray-800 hover:cursor-pointer",
|
||||
"focus:outline-none focus-visible:ring-1 focus-visible:ring-slate-500 dark:focus-visible:ring-gray-50 focus-visible:bg-slate-100 dark:focus-visible:bg-gray-800",
|
||||
"transition-colors hover:transition-none",
|
||||
)}
|
||||
>
|
||||
{displayValue}
|
||||
</button>
|
||||
<div className="flex items-center relative w-full">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setDialogOpen(true)}
|
||||
className={cn(
|
||||
"stack-scope flex w-full items-center rounded-xl border border-black/[0.08] dark:border-white/[0.06] bg-white/80 dark:bg-foreground/[0.03] shadow-sm ring-1 ring-black/[0.08] dark:ring-white/[0.06]",
|
||||
"h-8 px-3 text-sm text-left text-muted-foreground",
|
||||
"transition-all duration-150 hover:transition-none hover:bg-white dark:hover:bg-foreground/[0.06] hover:cursor-pointer",
|
||||
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-foreground/[0.1]",
|
||||
)}
|
||||
>
|
||||
<span className="truncate">{displayValue}</span>
|
||||
</button>
|
||||
</div>
|
||||
</UserInfo>
|
||||
<RestrictionDialog
|
||||
user={user}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user