Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
695131e
Polish analytics query editor surface.
Developing-Gamer May 27, 2026
d9177cb
Refresh analytics AI query controls.
Developing-Gamer May 27, 2026
a4a7b0f
Tighten analytics table layout.
Developing-Gamer May 27, 2026
3a2186d
Improve auth method review surfaces.
Developing-Gamer May 27, 2026
315add2
Refresh support conversations UI.
Developing-Gamer May 27, 2026
bdd3884
Polish project domains page.
Developing-Gamer May 27, 2026
34266ad
Refine email sender pages.
Developing-Gamer May 27, 2026
514fcc6
Polish launch checklist layout.
Developing-Gamer May 27, 2026
a120e73
Normalize project page shell spacing.
Developing-Gamer May 27, 2026
12744a2
Refresh product payment lists.
Developing-Gamer May 27, 2026
6bf8034
Rework session replay layout.
Developing-Gamer May 27, 2026
42e10ce
Polish sign-up rules page.
Developing-Gamer May 27, 2026
f8b95d5
Soften assistant thread surface.
Developing-Gamer May 27, 2026
93bb13f
Refine country code select styling.
Developing-Gamer May 27, 2026
89af885
Add dashboard user menu button.
Developing-Gamer May 27, 2026
b435624
Polish dashboard menu settings surfaces.
Developing-Gamer May 27, 2026
b4286aa
Refine rule builder conditions UI.
Developing-Gamer May 27, 2026
3ab5db9
Refresh action dialog chrome.
Developing-Gamer May 27, 2026
8eaac91
Align dashboard button dialog primitives.
Developing-Gamer May 27, 2026
8b8ada1
Align dashboard menu form primitives.
Developing-Gamer May 27, 2026
f4944f7
Refresh vibe coding layout.
Developing-Gamer May 27, 2026
15f4573
Polish dashboard UI feedback primitives.
Developing-Gamer May 27, 2026
9d3d586
Add data grid sizing helpers.
Developing-Gamer May 27, 2026
7050e96
Apply data grid sizing updates.
Developing-Gamer May 27, 2026
2a64025
Refresh dashboard UI dialog inputs.
Developing-Gamer May 27, 2026
4583e8e
Align dashboard UI tab exports.
Developing-Gamer May 27, 2026
c463180
Sync stack UI primitive styling.
Developing-Gamer May 27, 2026
a2feba0
Document dashboard-only account settings customization pattern.
Developing-Gamer May 27, 2026
9fb289d
Add account settings page layout and section primitives.
Developing-Gamer May 27, 2026
8a09b16
Add account settings sidebar layout for dashboard.
Developing-Gamer May 27, 2026
3083967
Add editable text component for account settings.
Developing-Gamer May 27, 2026
c2ce97e
Add profile image editor for account settings.
Developing-Gamer May 27, 2026
5ed337e
Add local types for dashboard account settings API keys.
Developing-Gamer May 27, 2026
3d7eee9
Add team icon component for dashboard account settings.
Developing-Gamer May 27, 2026
b629d5a
Add API key table for dashboard account settings.
Developing-Gamer May 27, 2026
0197cd5
Add API key create and show dialogs for account settings.
Developing-Gamer May 27, 2026
fce2134
Add profile page for dashboard account settings.
Developing-Gamer May 27, 2026
e0fa1c1
Add API keys page for dashboard account settings.
Developing-Gamer May 27, 2026
b53e2ab
Add email addresses section for dashboard account settings.
Developing-Gamer May 27, 2026
48e71ae
Add password section for dashboard account settings.
Developing-Gamer May 27, 2026
6ca19c6
Add passkey section for dashboard account settings.
Developing-Gamer May 27, 2026
232f125
Add OTP sign-in section for dashboard account settings.
Developing-Gamer May 27, 2026
77b10a8
Add MFA section for dashboard account settings.
Developing-Gamer May 27, 2026
adbf61b
Add emails and auth page for dashboard account settings.
Developing-Gamer May 27, 2026
fe392dd
Add notifications page for dashboard account settings.
Developing-Gamer May 27, 2026
6df13f5
Add active sessions page for dashboard account settings.
Developing-Gamer May 27, 2026
f245ea5
Add settings page with sign-out and delete account sections.
Developing-Gamer May 27, 2026
1068841
Add team settings pages and sections for dashboard account settings.
Developing-Gamer May 27, 2026
2674857
Wire dashboard account settings shell, payments, and handler route.
Developing-Gamer May 27, 2026
71faf25
Merge branch 'dev' into Consistency-and-design-changes-light-mode
Developing-Gamer May 27, 2026
af9155a
Extend knowledge base for dashboard account settings work.
Developing-Gamer May 27, 2026
3d3b6ab
Add dashboard dependencies for account settings MFA and image crop.
Developing-Gamer May 27, 2026
b5347f3
Align action dialog styling with dashboard UI patterns.
Developing-Gamer May 27, 2026
b17e2b6
Fix analytics AI query bar layout alignment.
Developing-Gamer May 27, 2026
7475b14
Simplify session replays page client layout.
Developing-Gamer May 27, 2026
8d62fe0
Refine dashboard account settings shell and sidebar items.
Developing-Gamer May 27, 2026
0ca4403
Refine profile editing components in account settings.
Developing-Gamer May 27, 2026
f716b82
Refine email addresses section in account settings.
Developing-Gamer May 27, 2026
974790e
Refine MFA section layout in account settings.
Developing-Gamer May 27, 2026
48c5f35
Refine OTP and passkey sections in account settings.
Developing-Gamer May 27, 2026
bc0d583
Refine payments page and team switcher in account settings.
Developing-Gamer May 27, 2026
b9e08ab
Refine API key dialogs and table in account settings.
Developing-Gamer May 27, 2026
35b1ab6
Refine active sessions page in account settings.
Developing-Gamer May 27, 2026
4ec3280
Refine team API keys and member invitation sections.
Developing-Gamer May 27, 2026
ae410d5
Fix dashboard account settings review comments.
Developing-Gamer May 27, 2026
c3b2810
smol layout fix
Developing-Gamer May 28, 2026
6c8ea14
Merge branch 'dev' into Consistency-and-design-changes-light-mode
Developing-Gamer May 28, 2026
fe867ba
fix
Developing-Gamer May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .claude/CLAUDE-KNOWLEDGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -563,5 +563,10 @@ A: Project config overrides only support the hosted `sourceOfTruth` shape. Legac
## Q: How should managed email onboarding e2e tests wait for mock verification?
A: Do not rely on a fixed `wait(1500)` after setup. The mock onboarding path flips the domain to `verified` asynchronously through `runAsynchronously`, so tests should poll the managed-onboarding check endpoint until the expected status appears.

## Q: How can we redesign or customize account settings pages for the dashboard only, without modifying any shared packages (like `@stackframe/stack` or `packages/template`)?
A: Intercept the catch-all dynamic route in `apps/dashboard/src/app/(main)/handler/[...stack]/page.tsx` on the server by awaiting `params` and checking if `stack.join("/") === "account-settings"`. If matched, completely bypass `StackHandler` and return a local, custom-built `DashboardAccountSettingsPage` Client Component. To implement the custom views cleanly, copy the necessary forms and layouts from `packages/template` into `apps/dashboard/src/components/dashboard-account-settings/`, replace the relative and package UI imports with local dashboard UI components (such as `@/components/ui/button`, `@/components/ui/input`, and local `Table` / `Badge` / `Switch` / `Avatar` / `Skeleton`), and custom style them with neutral, zinc/white border and card layers to match the dashboard's design system seamlessly.

## Q: What can make dashboard/docs Vercel builds fail after adding dashboard-only account settings code?
A: Dashboard-only imports still need direct dependency declarations in `apps/dashboard/package.json`; transitive workspace deps are not enough for CI/Vercel resolution. For example, imports of `@oslojs/otp`, `@stackframe/stack-ui`, `qrcode`, and `react-easy-crop` must be declared on the dashboard app itself. Also, placeholder comments like `NEXT_PUBLIC_STACK_PROJECT_ID=# ...` in `docs/.env` parse as empty values during `next build`; use real internal development defaults instead of comment-only assignments.
## Q: How should Microsoft OAuth callback token exchange include scopes?
A: Microsoft Entra ID's v2 token endpoint can reject authorization-code exchanges with `AADSTS70011` if the token request omits `scope`. Keep scope emission opt-in at the provider layer (`includeScopeInCallbackTokenExchange`) and pass the same merged base/provider scopes to `openid-client` via the callback `extras.exchangeBody.scope` parameter. The callback route must forward stored `providerScope` from the outer OAuth info so custom Microsoft provider scopes are included in the token exchange.
5 changes: 5 additions & 0 deletions apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@dnd-kit/utilities": "^3.2.2",
"@hookform/resolvers": "^3.3.4",
"@monaco-editor/react": "4.7.0",
"@oslojs/otp": "^1.1.0",
"@phosphor-icons/react": "^2.1.10",
"@radix-ui/react-accordion": "^1.2.1",
"@radix-ui/react-alert-dialog": "^1.1.2",
Expand Down Expand Up @@ -64,6 +65,7 @@
"@stackframe/dashboard-ui-components": "workspace:*",
"@stackframe/stack": "workspace:*",
"@stackframe/stack-shared": "workspace:*",
"@stackframe/stack-ui": "workspace:*",
"@stripe/connect-js": "^3.3.27",
"@stripe/react-connect-js": "^3.3.24",
"@stripe/react-stripe-js": "^3.8.1",
Expand All @@ -89,9 +91,11 @@
"next": "16.1.7",
"next-themes": "^0.2.1",
"posthog-js": "^1.336.1",
"qrcode": "^1.5.4",
"react": "19.2.3",
"react-day-picker": "^9.6.7",
"react-dom": "19.2.3",
"react-easy-crop": "^5.5.6",
"react-globe.gl": "^2.28.2",
"react-hook-form": "^7.53.1",
"react-icons": "^5.0.1",
Expand All @@ -114,6 +118,7 @@
"@types/canvas-confetti": "^1.6.4",
"@types/lodash": "^4.17.5",
"@types/node": "20.17.6",
"@types/qrcode": "^1.5.5",
"@types/react": "19.2.7",
"@types/react-dom": "19.2.3",
"@types/react-syntax-highlighter": "^15.5.13",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ function QueriesContent() {
value={sqlQuery}
onChange={(e) => setSqlQuery(e.target.value)}
placeholder="SELECT * FROM default.events ORDER BY event_at DESC LIMIT 100"
className="font-mono text-sm min-h-[80px] resize-y bg-background/60"
className="min-h-[80px] resize-y border-black/[0.08] bg-white/95 font-mono text-sm shadow-sm ring-1 ring-black/[0.06] dark:border-border/40 dark:bg-background/60 dark:ring-white/[0.06]"
onKeyDown={(e) => {
if (e.key === "Enter" && (e.metaKey || e.ctrlKey) && !loading) {
e.preventDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ export function AiQueryBar({
<div
className={cn(
"group flex h-8 min-w-0 flex-1 items-center gap-2 rounded-xl px-2.5 sm:max-w-72",
"bg-background ring-1 transition-shadow",
"border border-black/[0.08] dark:border-white/[0.06]",
"bg-white dark:bg-background shadow-sm ring-1 ring-black/[0.08] dark:ring-white/[0.06] transition-shadow hover:transition-none",
Comment thread
Developing-Gamer marked this conversation as resolved.
Comment thread
Developing-Gamer marked this conversation as resolved.
isActive
? "ring-purple-500/30 focus-within:ring-purple-500/50"
: "ring-black/[0.08] dark:ring-white/[0.08] focus-within:ring-foreground/[0.18]",
? "ring-purple-500/30 focus-within:ring-purple-500/50 dark:ring-purple-400/30 dark:focus-within:ring-purple-400/50"
: "hover:ring-black/[0.12] dark:hover:ring-white/[0.1] focus-within:ring-foreground/[0.18]",
)}
>
<SparkleIcon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ export function AiQueryDialog({
</div>
</DialogHeader>

<div className="shrink-0 border-b border-border/40 bg-muted/20">
<div className="shrink-0 border-b border-black/[0.06] bg-zinc-50/80 dark:border-border/40 dark:bg-muted/20">
<div className="flex items-center justify-between px-5 py-2">
<Label className="text-[10px] font-semibold uppercase tracking-wide text-muted-foreground">
Current query
Expand Down Expand Up @@ -417,7 +417,7 @@ export function AiQueryDialog({
}
}}
placeholder="Ask the AI a question to generate a query."
className="min-h-16 max-h-32 resize-y overflow-auto border-border/40 bg-background/70 font-mono text-[11px] text-foreground/90 shadow-none placeholder:italic placeholder:text-muted-foreground"
className="min-h-16 max-h-32 resize-y overflow-auto border-black/[0.08] bg-white/95 font-mono text-[11px] text-foreground/90 shadow-sm ring-1 ring-black/[0.06] placeholder:italic placeholder:text-muted-foreground dark:border-border/40 dark:bg-background/60 dark:ring-white/[0.06]"
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export default function PageClient() {
<AppEnabledGuard appId="analytics">
<PageLayout fillWidth noPadding>
<AnalyticsEventLimitBanner />
<div className="flex min-w-0 items-start lg:-mx-2 [--analytics-tables-sticky-top:3.5rem] [--analytics-tables-sidebar-height:calc(100vh-3.5rem)] dark:[--analytics-tables-sticky-top:5rem] dark:[--analytics-tables-sidebar-height:calc(100vh-6rem)]">
<div className="flex w-full min-w-0 items-stretch lg:-ml-2 [--analytics-tables-sticky-top:3.5rem] [--analytics-tables-sidebar-height:calc(100vh-3.5rem)] dark:[--analytics-tables-sticky-top:5rem] dark:[--analytics-tables-sidebar-height:calc(100vh-6rem)]">
{/* Left sidebar — hidden on mobile */}
<div
className="hidden lg:flex w-48 min-h-0 flex-shrink-0 self-start flex-col overflow-hidden border-r border-border/50 pl-2 sticky"
Expand Down Expand Up @@ -271,8 +271,19 @@ export default function PageClient() {
</div>
</div>

{/* Right content */}
<div className="flex min-w-0 flex-1 flex-col">
{/* Right content — flush to card edge; companion gap is on <main> in sidebar-layout */}
<div
className={cn(
"flex min-w-0 flex-1 flex-col",
"[&_[role=grid]]:rounded-r-none",
"[&_[role=grid]_.sticky]:rounded-t-none",
// Toolbar row only (first child of sticky chrome) — analytics layout
"[&_[role=grid]_.sticky>div:first-child>div]:pt-3",
"[&_[role=grid]_.sticky>div:first-child>div]:pb-2.5",
"[&_[role=grid]_.sticky>div:first-child>div]:pr-0",
"[&_[role=grid]_.sticky>div:first-child>div]:pl-2.5",
)}
>
{selectedTable ? (
<TableContent key={selectedTable} tableId={selectedTable} />
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ export const QueryDataGrid = forwardRef<QueryDataGridHandle, QueryDataGridProps>
)}

{!showEmptyError && (
<div className={fillHeight ? "flex-1 min-h-0 pr-0 lg:pr-8" : "pr-0 lg:pr-8"}>
<div className={fillHeight ? "flex-1 min-h-0" : undefined}>
<DataGrid<RowData>
columns={columns}
rows={gridData.rows}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ function DisabledProvidersDialog({ open, onOpenChange }: { open?: boolean, onOpe
placeholder="Search for a provider..."
value={providerSearch}
onChange={(e) => setProviderSearch(e.target.value)}
leadingIcon={<MagnifyingGlassIcon size={14} />}
leadingIcon={<MagnifyingGlassIcon className="h-3.5 w-3.5" />}
/>
<div className="flex gap-2 flex-wrap justify-center">
{filteredProviders
Expand Down Expand Up @@ -448,6 +448,7 @@ function useEmailVerificationToggle() {
open={!!pendingChange}
onClose={() => setPendingChange(null)}
title="Enable email verification requirement"
size="2xl"
danger
okButton={{
label: "Apply Change",
Expand All @@ -468,35 +469,50 @@ function useEmailVerificationToggle() {
<Typography variant="secondary" type="label">
Affected users
</Typography>
<div className="rounded-xl ring-1 ring-black/[0.06] dark:ring-white/[0.06] overflow-hidden">
<table className="w-full text-sm">
<thead className="bg-foreground/[0.04]">
<div className="overflow-hidden rounded-xl ring-1 ring-black/[0.06] dark:ring-white/[0.06]">
<table className="w-full table-fixed text-sm">
<colgroup>
<col className="w-[22%]" />
<col />
<col className="w-[7.5rem]" />
</colgroup>
<thead className="bg-zinc-50 dark:bg-background">
<tr>
<th className="px-3 py-2 text-left font-medium">User</th>
<th className="px-3 py-2 text-left font-medium">Email</th>
<th className="px-3 py-2 text-left font-medium">Reason</th>
<th className="px-3 py-2 text-left font-medium whitespace-nowrap">Reason</th>
</tr>
</thead>
<tbody>
{pendingChange.affectedUsers.map((user) => (
<tr key={user.id} className="border-t border-black/[0.06] dark:border-white/[0.06]">
<td className="px-3 py-2">
{user.displayName || <span className="text-muted-foreground italic">No name</span>}
</td>
<td className="px-3 py-2">
{user.primaryEmail || <span className="text-muted-foreground italic">No email</span>}
</td>
<td className="px-3 py-2">
<DesignBadge
label={user.restrictedReason.type === "email_not_verified" ? "Email not verified" : "Anonymous user"}
color="orange"
size="sm"
/>
</td>
</tr>
))}
</tbody>
</table>
<div className="max-h-52 overflow-y-auto border-t border-black/[0.06] dark:border-white/[0.06]">
<table className="w-full table-fixed text-sm">
<colgroup>
<col className="w-[22%]" />
<col />
<col className="w-[7.5rem]" />
</colgroup>
<tbody>
{pendingChange.affectedUsers.map((user) => (
<tr key={user.id} className="border-t border-black/[0.06] dark:border-white/[0.06] first:border-t-0">
<td className="px-3 py-2 align-middle">
{user.displayName || <span className="text-muted-foreground italic">No name</span>}
</td>
<td className="px-3 py-2 align-middle truncate" title={user.primaryEmail ?? undefined}>
{user.primaryEmail || <span className="text-muted-foreground italic">No email</span>}
</td>
<td className="px-3 py-2 align-middle">
<DesignBadge
label={user.restrictedReason.type === "email_not_verified" ? "Not verified" : "Anonymous"}
color="orange"
size="sm"
contentMode="text"
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{pendingChange.totalAffectedCount > pendingChange.affectedUsers.length && (
<Typography variant="secondary" type="footnote">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@ export const providerFormSchema = yupObject({

export type ProviderFormValues = yup.InferType<typeof providerFormSchema>

/** Modal chrome — "Floating soft" (variant G). */
const PROVIDER_DIALOG_CHROME_CLASS = "border-0 rounded-3xl bg-background shadow-2xl shadow-black/30 dark:shadow-black/60";

function ProviderHeader({ providerId }: { providerId: string }) {
return (
<div className="flex items-center gap-3">
Expand Down Expand Up @@ -329,7 +326,6 @@ export function ProviderSettingDialog(props: Props & { open: boolean, onClose: (
title={`${toTitle(props.id)} OAuth provider`}
cancelButton
okButton={{ label: 'Save' }}
contentClassName={PROVIDER_DIALOG_CHROME_CLASS}
render={(form) => (
<OAuthProviderSettingsForm
form={form}
Expand Down
Loading
Loading